App应用字体大小保持固定以及关于Configuration的变化

来源:互联网 发布:调度算法计算题 编辑:程序博客网 时间:2024/06/06 06:44

前言

安卓4.0之后系统设置->显示里面新增了字体大小设置的选项.看下你自己的安卓机,如果你将字体大小从小号一直增大到特大号,有没有发现某些安装的app里面的字体大小也随着变化了?这样可能是便于了阅读,但是app里面本来能显示完全的内容可能因此就只显示了部分.实际上,我们可以看一下QQ、淘宝等大厂的应用,里面的字体大小并不会随着系统设置的大小而变化.

初始解决方法

网上早已给出了解决办法,在Application,也就是app定义的入口处添加以下代码:

@Overridepublic void onCreate(){    super.onCreate();    Resources resources = getResources();    resources.getConfiguration().fontScale = 1.0f;    resources.updateConfiguration(null, null);}

就是说,在应用初始化的时候,通过上下文得到应用的资源,进而得到对应于当前应用资源的配置(Configuration),将配置里代表字体缩放的变量(fontScale)置为1,也就是默认值,不进行任何缩放.

新的问题

这时候如果先设置好系统字体的大小为超大或其它,再次进入应用,字体仍然保持之前的大小.但是!如果你没有对该页面(设定最简单的情况,是一个Activity)进行任何设置,那么切换屏幕方向,比如从竖屏到横屏,会发现字体大小又变化了,本来可以显示完全的现在换行了.日志打印获取其字体大小也可以证明确实是变化了:

I/MainActivity_LOG: 该页面重新创建
I/MainActivity_LOG: 字体的大小:48.0
I/MainActivity_LOG: onStart
I/MainActivity_LOG: onResume
I/MainActivity_LOG: onPause
I/MainActivity_LOG: onStop
I/MainActivity_LOG: onDestroy
I/MainActivity_LOG: 该页面重新创建
I/MainActivity_LOG: 字体的大小:62.0

意识到可能跟屏幕方向切换后,页面销毁后重新创建的过程有关.而屏幕方向是设备配置的一个属性,屏幕旋转又是影响配置变化的因素之一.所以要看一下Configuration Change.

Configuration变化后页面的生命周期

public class MainActivity extends AppCompatActivity {    public static final String TAG = "MainActivity_LOG";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Log.i(TAG, "该页面重新创建");        TextView textView = findViewById(R.id.textView);        float textSize = textView.getTextSize();        Log.i(TAG, "字体的大小:" + textSize);    }    @Override    public void onConfigurationChanged(Configuration newConfig) {        super.onConfigurationChanged(newConfig);        Log.i(TAG, "config更新了");    }    @Override    protected void onStart() {        super.onStart();        Log.i(TAG, "onStart");    }    @Override    protected void onResume() {        super.onResume();        Log.i(TAG, "onResume");    }    @Override    protected void onPause() {        super.onPause();        Log.i(TAG, "onPause");    }    @Override    protected void onStop() {        super.onStop();        Log.i(TAG, "onStop");    }    @Override    protected void onDestroy() {        super.onDestroy();        Log.i(TAG, "onDestroy");    }}

查看日志后,发现:
1.清单文件中不声明任何属性,切屏后Activity销毁后重建,重新走了一遍生命周期,并且不会回调onConfiguration方法,切横屏和切竖屏都是.日志如下:

I/MainActivity_LOG: onPause
I/MainActivity_LOG: onStop
I/MainActivity_LOG: onDestroy
I/MainActivity_LOG: 该页面重新创建
I/MainActivity_LOG: onStart
I/MainActivity_LOG: onResume

2.在清单文件中声明Activity的android:configChanges属性,如果只是单独声明orientation或者screenSize,和没有声明的情况一样.

3,在清单文件中声明android:configChanges="orientation|screenSize",才可以成功回调onConfigurationChanged方法.并且此时不会销毁当前的Activity,也就是不会重走各个生命周期.

原因分析

到这大概可以清楚,虽然应用初始化的时候更新了Configure的fontScale=1,但如果出现了销毁页面重新创建的情况,之前保存的配置就会失效.其实稍微看一下源代码就明白了,调用getResources().getConfiguration()返回的是在ResourcesImpl类中初始化的时候创建的Configuration对象,调用其无参构造方法后,最终调用的是unSet方法:

public void unset() {    setToDefaults();    fontScale = 0;}

该方法最终将字体缩放值置为0,也就是适应系统字体的变化,就出现了前面说的问题.

Configuration Changes引起的其它情况

一开始,我采取的是配置清单文件中Activity的属性,比如将屏幕的方向写死android:screenOrientation="portrait",或者避免Activity销毁重建android:configChanges="orientation|screenSize",这样做的话,旋转屏幕不会造成已修改的配置失效.但是引起Configuration Changes的情况很多,不仅仅是切屏:比如修改设备的默认语言,修改系统字体大小.从打印日志可以看出这时候页面仍然进行了销毁和重建的过程,已更新的字体大小配置又失效了.

解决方法

现在提供了一种解决方法,虽然不太优雅.既然外部的各种操作无法全部考虑到,并且都可能会引发页面的销毁和重建,也就是说无法控制Configuration的重置,在不能修改API的情况下,能想到的就是在基类BaseActivity(或其它)初始化的时候都调用一下更新字体配置的方法.或者更好一点的方式,Application提供了一个监听方法registerActivityLifecycleCallbacks,可以全局监听应用里面所有已声明的Activity的生命周期.当监听到应用创建的时候,都更新一下.

public class MainApplication extends Application {    @Override    public void onCreate() {        super.onCreate();        this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {            @Override            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {                Resources resources = getResources();                resources.getConfiguration().fontScale = 1.0f;                resources.updateConfiguration(null, null);            }            @Override            public void onActivityStarted(Activity activity) {            }            @Override            public void onActivityResumed(Activity activity) {            }            @Override            public void onActivityPaused(Activity activity) {            }            @Override            public void onActivityStopped(Activity activity) {            }            @Override            public void onActivitySaveInstanceState(Activity activity, Bundle outState) {            }            @Override            public void onActivityDestroyed(Activity activity) {            }        });    }}

总结

关于字体大小还有一种解决方式,就是在布局文件中全部用px表示,因为手机的分辨率就是以px定义的,所以无论系统怎么设置字体大小,配置如何更新,显示在界面上的字体大小都是固定的.当然这也带来了适配的问题,因为谷歌官方建议用dp定义尺寸的.这涉及到了安卓的屏幕兼容性问题,可以用鸿洋的方法解决:Android屏幕适配方案.不过这种方法自己根据屏幕分辨率计算出的以160dpi为基准的px大小,没有考虑到屏幕尺寸,也是无法解决所有的问题.
目前我测试没有发现明显的问题,当然方式有点简单粗暴.如果有更好的实现方式,也希望各位能告诉我一下,欢迎交流.

阅读全文
0 0
原创粉丝点击