Android 修改字体工具类

使用注解枚举和反射

public final class TypefaceManager {

    public static final int FONT_TYPE_ICONIC = 0;
    public static final int FONT_TYPE_IMPACT = 1;
    public static final int FONT_TYPE_HELVETICA = 2;
    public static final int FONT_TYPE_DIN = 3;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({FONT_TYPE_ICONIC, FONT_TYPE_IMPACT, FONT_TYPE_HELVETICA, FONT_TYPE_DIN})
    @interface FontType {
    }

    private Context mContext;
    private SparseArray mTypefaceSparseArray;

    public TypefaceManager(Context context) {
        this.mContext = context;
        this.mTypefaceSparseArray = new SparseArray<>();
    }

    // 修改单独TextView的字体
    public static void setTypeface(TextView textView, @FontType int fontType) {
        Typeface localTypeface = MyApplication
                                    .getInstance()
                                    .getTypefaceManager()
                                    .getTypeface(fontType);
        if (localTypeface != null && localTypeface != textView.getTypeface()) {
            textView.setTypeface(localTypeface);
        }
    }

    // 修改Paint 的字体(主要对自定义View)
    public static void setTypeface(Paint paint, @FontType int fontType) {
        Typeface localTypeface = MyApplication
                                    .getInstance()
                                    .getTypefaceManager()
                                    .getTypeface(fontType);
        if (localTypeface != null && localTypeface != paint.getTypeface()) {
            paint.setTypeface(localTypeface);
        }
    }

    private Typeface getTypeface(@FontType int fontType) {
        Typeface typeface = mTypefaceSparseArray.get(fontType);
        if (typeface == null) {
            try {
                String path = null;
                if (fontType == FONT_TYPE_ICONIC) {
                    path = "fonts/fontawesome-webfont.ttf";
                } else if (fontType == FONT_TYPE_IMPACT) {
                    path = "fonts/impact.ttf";
                } else if (fontType == FONT_TYPE_HELVETICA) {
                    path = "fonts/Helvetica.ttf";
                } else if (fontType == FONT_TYPE_DIN) {
                    path = "fonts/ptdin.ttf";
                }
                typeface = Typeface.createFromAsset(mContext.getAssets(), path);
                this.mTypefaceSparseArray.put(fontType, typeface);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return typeface;
    }

    /**
     * 通过改变App的系统字体替换App内部所有控件的字体
     *
     * @param oldFontName       
     *    支持的名称有 MONOSPACE、SERIF,NORMAL(程序无法运行)、SANS与DEFAULT
     *    和DEFAULT_BOLD与SANS_SERIF(可以运行但是显示字体没有修改成功)
     *    而且需要与AndroidManifest文件application的android:theme引用的styles文件中
     *    monospace 的值对应
     *
     * @param newFontNameFromAssets 
     *    新的字体路径,必须要放在assets文件夹下,如:fonts/Nsimsun.ttf
     */
    public static void replaceSystemDefaultFont(String oldFontName, @FontType int fontType) {
        Typeface newTypeface= MyApplication
                                    .getInstance()
                                    .getTypefaceManager()
                                    .getTypeface(fontType);
        try {
            //android 5.0及以上我们反射修改Typeface.sSystemFontMap变量
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                Map newMap = new HashMap<>();
                newMap.put(oldFontName, newTypeface);
                final Field staticField = Typeface.class.getDeclaredField("sSystemFontMap");
                staticField.setAccessible(true);
                staticField.set(null, newMap);
            } else {
                final Field staticField = Typeface.class.getDeclaredField(oldFontName);
                staticField.setAccessible(true);
                staticField.set(null, newTypeface);
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

其中,replaceSystemDefaultFont设置全局字体变化时,参数oldFontName必须和applicationandroid:theme引用的styles文件中 monospace的值对应。
如下图:


你可能感兴趣的:(Android 修改字体工具类)