设置自定义字体有一下几种方式:
方法一.自定义View
1 . 把字体资源放在assets文件夹底下,可以新建一个fonts的文件夹
2 . 自定义View继承TextView:
public class CustomFontTextView extends TextView {
public CustomFontTextView(Context context) {
super(context);
init(context);
}
public CustomFontTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public CustomFontTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void init(Context context) {
Typeface newFont = Typeface.createFromAsset(context.getAssets(), "fonts/MyFont.ttf");
setTypeface(newFont);
}
}
3 . 使用自定义的TextView.
方法二. 遍历ViewGroup
我们会发现,第一种方法其实只适用于局部位置修改字体,例如整个布局页面都像要设置自定义字体怎么办呢?我们可以这样做:
public class FontHelper {
public static final void setAppFont(ViewGroup mContainer, Typeface mFont, boolean reflect) {
if (mContainer == null || mFont == null) return;
for (int i = 0; i < mContainer.getChildCount(); ++i) {
final View mChild = mContainer.getChildAt(i);
if (mChild instanceof TextView) {
((TextView) mChild).setTypeface(mFont);
} else if (mChild instanceof EditText) {
((EditText) mChild).setTypeface(mFont);
//你可以在这里添加自定义字体的其他类型的view
} else if (mChild instanceof ViewGroup) {
setAppFont((ViewGroup) mChild, mFont, true);
} else if (reflect) {
try {
Method mSetTypeface = mChild.getClass().getMethod("setTypeface", Typeface.class);
mSetTypeface.invoke(mChild, mFont);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
在Activity的onCreate和Fragment的onCreateView等地方使用:
final Typeface mFont = Typeface.createFromAsset(getAssets(),
"fonts/Roboto-Light.ttf");
final ViewGroup mContainer = (ViewGroup) findViewById(
android.R.id.content).getRootView();
FontHelper.setAppFont(mContainer, mFont, true);
方法三. 遍历全局映射替换
其实这个方法才是我们绝大多数数时候想要用的, 一次性替换应用全部字体.
由于官方并没有提供相应的接口,所以这里我们采用的方式时通过反射,获取Typeface类的静态成员变量,并修改对应的字体文件.
这里根据你使用的主题和API的不同,处理方式也有所区别:
1. 非Theme.Material主题
比如你使用的是Theme.Holo主题,或Theme.AppCompat主题, 首先定义一个工具:
public final class FontsOverride {
public static void setDefaultFont(Context context,
String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(),
fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}
protected static void replaceFont(String staticTypefaceFieldName,
final Typeface newTypeface) {
try {
final Field staticField = Typeface.class
.getDeclaredField(staticTypefaceFieldName);
staticField.setAccessible(true);
staticField.set(null, newTypeface);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
然后在主题里指定使用某种字体(android lollipop设置有区别):
values
<resources>
<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
</style>
<!-- Application theme. -->
<style name="AppTheme" parent="AppBaseTheme">
<item name="android:typeface">monospace</item>
</style>
</resources>
values-v21
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light">
<item name="android:textAppearance">@style/CustomTextAppearance
</item>
</style>
<style name="CustomTextAppearance">
<item name="android:typeface">monospace</item>
</style>
</resources>
最后在你的Application的onCreate()方法里面使用:
FontsOverride.setDefaultFont(this, "MONOSPACE", "fonts/MyFont.ttf");
2. 非Theme.Material主题
Theme.Material主题是Android 5.0新增的主题
public final class FontsOverride {
public static void setDefaultFont(Context context,
String staticTypefaceFieldName, String fontAssetName) {
final Typeface regular = Typeface.createFromAsset(context.getAssets(),
fontAssetName);
replaceFont(staticTypefaceFieldName, regular);
}
protected static void replaceFont(String staticTypefaceFieldName,
final Typeface newTypeface) {
//android 5.0及以上我们反射修改Typeface.sSystemFontMap变量
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Map<String, Typeface> newMap = new HashMap<>();
newMap.put(staticTypefaceFieldName, newTypeface);
try {
final Field staticField = Typeface.class
.getDeclaredField("sSystemFontMap");
staticField.setAccessible(true);
staticField.set(null, newMap);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
} else {
try {
final Field staticField = Typeface.class
.getDeclaredField(staticTypefaceFieldName);
staticField.setAccessible(true);
staticField.set(null, newTypeface);
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
//Material主题默认字体为sans-serif,暂时未找到自定义修改字体的方法
FontsOverride.setDefaultFont(this, "sans-serif", "fonts/Roboto-Light.ttf");
方法四. 使用开源库
如使用第三方库Calligraphy, 我没使用过,如果有感兴趣的可以自己尝试一下.