使用注解枚举和反射
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<Typeface> 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文件中
* <item name="android:typeface">monospace</item> 的值对应
*
* @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<String, Typeface> 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
必须和application
的android:theme
引用的styles
文件中<item name = "android:typeface"> monospace</item>
的值对应。
如下图:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<!-- Set system default typeface -->
<item name="android:typeface">monospace</item>
</style>