关于Android切换系统字体大小和字体样式导致App崩溃或者界面错乱的问题

测试小姐姐测试版本的时候,把系统字体给变大了,再回到app直接崩溃,分析原因找问题,主要有2种方式
第一种.设置字体大小我们都是用的是sp,如果改为dp就不会有这个问题, 我相信大部分写android的都是用的sp,现在改回来肯定是头痛,别着急,我们先看看源码

 
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;
    }

  

density不会受到用户配置的影响,而scaledDensity除了会受到用户配置的影响,其它方面是跟density一致的。
终于真相大白!因此使用 sp 单位时字体大小会受到用户配置系统字体的影响。
但是这种方式还是不推荐.

第二种
直接通过代码控制,不跟随系统改变字体

/**
  * 重写 getResource 方法,防止系统字体影响
 */
    @Override
    public Resources getResources() {//禁止app字体大小跟随系统字体大小调节
        Resources resources = super.getResources();
        if (resources != null && resources.getConfiguration().fontScale != 1.0f) {
            android.content.res.Configuration configuration = resources.getConfiguration();
            configuration.fontScale = 1.0f;
            configuration.setToDefaults();//设置默认 不能使用这个,会修改很多对方的属性值,比如在5.1版本适配有问题
            resources.updateConfiguration(configuration, resources.getDisplayMetrics());
        }
        return resources;
    }

这样又有这个问题,Android 8.0上会发现这样修改字体的缩放比例是不起作用.需要在Activity中同样进行复写getResources()方法。

还得注意一个问题,切换了系统字体后,回到Activity会重启当前页面,为了避免这种问题,需要在:在manifest中的Activity中添加: android:configChanges="orientation|screenSize|keyboardHidden|fontScale"

这样可能就完美解决问题了

解决完上面的问题了,有善于思考的同学就问了,这个是解决切换系统的字体大小产生的问题,如果我切换系统字体的样式呢?出现问题又该怎么解决?

其实有了上面的基础,解决这个问题就容易的多了。

在切换字体大小的时候,我们知道系统会发送通知,我们设置fontScale属性就可以了。但是切换字体的样式,系统并没有通知,谷歌官方也没有,stack上也是各种提问,没有找到监听的事件或者方法。

切换样式之后,我们可以观察一下Activity的生命周期,依然是onDestroy(),onCreate()....因为是异常的destroy,系统会把当前的状态信息存入saveInstanceState()方法里面的bundle,onCreate()的时候,从bundle里面取出来进行恢复。有时候,保存的bundle状态不对,导致界面加载错乱。

解决的方法:

在onCreate()的时候,判断bundle里面是否有数据,如果有数据,进行赋空处理,然后走一遍正常的流程,就可以了。具体代码如下:

@Override

protectedvoidonCreate(Bundle savedInstanceState) {

if(null!= savedInstanceState){
savedInstanceState =null;
}

super.onCreate(savedInstanceState);}

  这个配置可以放在项目的BaseActivity里面,可以减少对现有代码的改动。

思考:其实这个时候,你会发现,在切换字体大小的时候,也可以这样配置,甚至这样配置之后就不用管fontScale之类的属性了,让界面自己刷新去吧,反正第二次的onCreate()跟重新进入app效果是一样的。






posted on 2024-06-12 17:52  巫山老妖  阅读(41)  评论(0编辑  收藏  举报