Android系统字体大小如何影响app的字体大小?

在Android应用开发过程中,一定会碰到本来完美的布局,在系统字体大小设置【最大】时变成一团浆糊。解决办法网上也有很多,但是分析原理的却几乎没看到。博主在碰到问题的第一时间也是直接用了网上的方法,即在BaseActivity中重写getResources方法如下

@Override  
public Resources getResources() {  
    Resources res = super.getResources();    
    Configuration config=new Configuration();    
    config.setToDefaults();    
    res.updateConfiguration(config,res.getDisplayMetrics());  
    return res;  
}

这个方法是有效的。
但是作为开发人员必须懂得举一反三,而要举一反三就必须要“知其所以然”,于是博主就去探寻了一番,才有了此篇文章。

1.字体大小如何设置

  • 这个简单,就拿TextView来说,设置字体大小调用setTextSize方法就行了。如果你直接以px为单位设置字体大小,那么应用字体大小是绝对不会被系统字体所影响的,但是绝大多数时候,我们用的单位都是sp,sp是什么?sp = scaled pixel 即缩放了的像素值。而如果用了sp就一定会受系统字体大小的影响。
    我们拿TextView来举例,看看它的setTextSize方法
public void setTextSize(int unit, float size) {
        Context c = getContext();
        Resources r;

        if (c == null)
            r = Resources.getSystem();
        else
            r = c.getResources();

        setRawTextSize(TypedValue.applyDimension(
                unit, size, r.getDisplayMetrics()));
    }
  • 看一眼代码,至少可以确定一件事情:设置的字体大小在内部做了计算和变换。
    没错,就是这个applyDimension方法干的好事!!
    我们跟进去看看先:
 public static float applyDimension(int unit, float value,
                                       DisplayMetrics metrics)
    {
        switch (unit) {
        case COMPLEX_UNIT_PX:
            return value;
        case COMPLEX_UNIT_DIP:
            return value * metrics.density;
        case COMPLEX_UNIT_SP://看这里,看这里
            return value * metrics.scaledDensity;
        case COMPLEX_UNIT_PT:
            return value * metrics.xdpi * (1.0f/72);
        case COMPLEX_UNIT_IN:
            return value * metrics.xdpi;
        case COMPLEX_UNIT_MM:
            return value * metrics.xdpi * (1.0f/25.4f);
        }
        return 0;
    }
  • 事实一目了然,我们设置进去的value值,这个方法返回的是value*metrics.scaledDensity 问题肯定出在scaledDensity这个属性身上!!!
    好了,字体大小的设置到此结束。

2. scaledDensity真面目

  • 根据网上提供的办法,我们知道字体大小的影响跟Resources有关(具体原因待分析)。于是博主在Resources.java源码中进行了查找,发现了一个重要的方法
public void updateConfiguration(Configuration config,
            DisplayMetrics metrics) {
        updateConfiguration(config, metrics, null);
    }

然后是具体实现的方法:

public void updateConfiguration(Configuration config,
            DisplayMetrics metrics, CompatibilityInfo compat) {
        synchronized (mAccessLock) {
            ... 省略代码 ...

            mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;

            ... 省略代码 ...
        }
        synchronized (sSync) {
            if (mPluralRule != null) {
                mPluralRule = NativePluralRules.forLocale(config.locale);
            }
        }
    }
  • 相信大家都看到了,mMetrics.scaledDensity的值其实是受mConfiguration.fontScale影响的。那么我们的研究对象又一次转变了,变成了fontScale。
    此时,我们对照一下,网上的解决系统字体大小影响的代码片段
@Override  
public Resources getResources() {  
    Resources res = super.getResources();    
    Configuration config=new Configuration();    
    config.setToDefaults();    
    res.updateConfiguration(config,res.getDisplayMetrics());  
    return res;  
}
  • 看来路子是走对了,这里也是对Configuration进行了设置,并且还调用了updateConfiguration方法。
    并且我还告诉你,这里的config.setToDefaults()方法内部第一句代码就是fontScale=1。
    那么分析到这里,我们基本可以推测:如果修改系统的字体大小,fontScale肯定会改变!

3. 最终解决

首先,推测是需要验证的。我们可以编写一个demo,在MainActivity的onCreate方法中打印fontScale值

 Log.d("Javine","fontScale = "+getResources().getConfiguration().fontScale);
  • 博主的是锤子T1,打印出来的结果是
    标准 —– fontScale = 1.0
    较大 —– fontScale = 1.1
    最大 —– fontScale = 1.4
    到此为止,我们还是不能百分之百确定问题一定是因为fontScale值的变化引起的。
    我们还需要做最后一件事情——通过修改fontScale值来修复字体大小的问题!
    跟网上的解决办法一样,重载Activity的getResources方法如下:
@Override
    public Resources getResources() {
        //获取到resources对象
        Resources res = super.getResources();
        //修改configuration的fontScale属性
        res.getConfiguration().fontScale = 1;
        //将修改后的值更新到metrics.scaledDensity属性上
        res.updateConfiguration(null,null);
        return res;
    }

经博主测试,问题完美解决!!并且,对比网上的解决办法,我们并没有新建一个Configuration对象,从性能角度上说,这个办法更优。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值