很多应用程序都有替换字体的需求,主要是设计可能要显示一个独特的字体,比如有多少人,花费了多少钱,这种用不同的字体显示会有强提醒的作用,增强应用程序的体验。
替换字体又一般分为部分替换,比如只正对一行显示中的某一段或者某一个数字进行替换,
我们知道系统中我们可以对字体显示View设置android:typeface属性,一般都有以下几种值可以选择:在手机上四中typeface替换,展示效果差距不大。
monospace
sanf
serif
normal
那如何才能自己用自定义的字体库来进行替换呐?
局部替换
一般都采用以下方法:针对要显示的TextView设置不同的Typeface,我们可以将一个ttf字库构造成一个Typeface,将构造的Typeface设置到要显示的TextView。这种比较方便的是字体库比较小,如果明确知道要显示的字库是什么,我们就可以只针对该字库来进行ttf生成。可以在一些开源的平台进行ttf的生成。ttf生成链接 样例代码如下
private static Typeface typeface;
TextView tv = new TextView(this);
tv.setTypeface(getTypeface(context));
public static Typeface getTypeface(Context context){
if (typeface == null) {
typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Roboto_Light.ttf");
}
return typeface;
}
只要对TextView设置setTypeface就可以了。
上面说到了局部的替换,如果全局需要替换又要怎么办。全局替换一般会采用以下几种方法,
全局替换
1: 遍历所有的view,在页面加载的时候进行全局设置Typeface,比如我们只针对TextView进行设置:
public void setTypeface(ViewGroup root, Typeface typeface){
if(root==null || typeface==null){
return;
}
int count = root.getChildCount();
for(int i=0;i<count;++i){
View view = root.getChildAt(i);
if(View instanceof TextView){
((TextView)view).setTypeface(typeface);
}else if(View instanceof ViewGroup){
setTypeface((ViewGroup)view, typeface);
}
}
}
2:想当然认为只要替换掉系统默认的Typeface是否就可以生效那,我们采用反射替换掉系统默认的Typeface。替换时机为Application加载的时候,可以在Application的onCreate中进行替换。
public final class AppTypeface {
private enum DefaultFont {
DEFAULT("DEFAULT"),
DEFAULT_BOLD("DEFAULT_BOLD"),
MONOSPACE("MONOSPACE"),
SERIF("SERIF"),
SANS_SERIF("SANS_SERIF");
private String value;
DefaultFont(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
public static boolean replace = false;
public static final String REPLACE_FONT = "fonts/Roboto_Light.ttf";
/**
* @param context
*/
public static final void init(Context context) {
if (replace) {
final Typeface replace = Typeface.createFromAsset(context.getAssets(), REPLACE_FONT);
for (DefaultFont defaultFont : DefaultFont.values()) {
replaceFont(defaultFont.getValue(), replace);
}
}
}
public static final void replaceFont(String fontName, Typeface typeface) {
try {
final Field staticField = Typeface.class.getDeclaredField(fontName);
staticField.setAccessible(true);
staticField.set(null, typeface);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
但是最终验证效果为,只单单是代码层面的替换,是没有效果的,在网上搜寻方案是发现代码替换与theme主题结合是能够生效的。theme设置如下:
<style name="LightBaseTheme" parent="Theme.AppCompat.Light">
<item name="android:typeface">monospace</item>
</style>
但是全局替换会面临如下的问题:
1:字体库的生成,如果是英文应用,ASCII表就基本就包括了所有需要替换的字符,但是中文应用,大家都知道的是,中文字符一共有10万多个,就算最常用的也有好几千,我在阿里妈妈webfont上试着生成一个包含常用字体的ttf,发现该平台最多支持7500多个字,再多就不能生成,这样会导致应用恰好包含了未替换的字体,展示效果很差。
2:如果不考虑ttf字体库的大小,搜索下来发现一般一个ttf就有10M,这样的大小对应用来说安装包增长太大,可以预见的是,包越大用户安装的意愿就越小。
3:上面的方法虽然在我手头的机器都是有效果的,但是不保证所有的机器都有效果。可能会出现加载错误或者渲染错误。