Android应用字体替换

很多应用程序都有替换字体的需求,主要是设计可能要显示一个独特的字体,比如有多少人,花费了多少钱,这种用不同的字体显示会有强提醒的作用,增强应用程序的体验。

替换字体又一般分为部分替换,比如只正对一行显示中的某一段或者某一个数字进行替换,

我们知道系统中我们可以对字体显示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:上面的方法虽然在我手头的机器都是有效果的,但是不保证所有的机器都有效果。可能会出现加载错误或者渲染错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值