需求
部分用户将系统字体大小设置的非常大,导致APP的文字大小显示异常。
想要实现的效果是,APP内字体大小不随系统设置的“字体大小”变化。
原始效果
系统的字体大小设置为“超大”时:(字体大小 可变)
目标效果
系统的字体大小设置为“超大”时:(字体大小 不变)
系统设置中,字体大小设置为 “超大”
示例代码
Android/FontScale · 宋冠巡/示例 - 码云 - 开源中国 ()
解决方案
原理
基类Activity,在初始化Context时,将字体缩放比例(fontScale)始终设置为1。
实现方法
在基类 BaseActivity 中,重写 attachBaseContext() 方法。
说明
attachBaseContext() 方法,在 onCreate() 方法之前调用,Activity获取构建页面所需的上下文配置时调用此方法。
在 attachBaseContext() 中,修改Configuration的内容,可以实现整个页面配置的修改,也就能实现字体大小的控制。
所有Activity均需要继承BaseActivity。因为将配置修改放置在了BaseActivity中,所以可以对整个APP的Activity页面生效。
具体实现
Kotlin 实现
核心代码
override fun attachBaseContext(newBase: Context?) {super.attachBaseContext(getConfigurationContext(newBase))}private fun getConfigurationContext(context: Context?): Context? {if (context == null) {return null}val configuration = context.resources.configurationconfiguration.fontScale = 1freturn context.createConfigurationContext(configuration)}
BaseActivity 完整代码 - Compose
package com.example.fontscaleimmutabledemocomposeimport android.content.Contextimport ponentActivity/*** 所有Activity的基类** @author songguanxun* @date /10/21*/open class BaseActivity : ComponentActivity() {override fun attachBaseContext(newBase: Context?) {super.attachBaseContext(getConfigurationContext(newBase))}private fun getConfigurationContext(context: Context?): Context? {if (context == null) {return null}val configuration = context.resources.configurationconfiguration.fontScale = 1freturn context.createConfigurationContext(configuration)}}
BaseActivity 完整代码 - View
package com.example.fontscaleimmutabledemokotlinimport android.content.Contextimport androidx.appcompat.app.AppCompatActivity/*** 所有Activity的基类** @author songguanxun* @date /10/21*/open class BaseActivity : AppCompatActivity() {override fun attachBaseContext(newBase: Context?) {super.attachBaseContext(getConfigurationContext(newBase))}private fun getConfigurationContext(context: Context?): Context? {if (context == null) {return null}val configuration = context.resources.configurationconfiguration.fontScale = 1freturn context.createConfigurationContext(configuration)}}
Java 实现
@Overrideprotected void attachBaseContext(Context newBase) {super.attachBaseContext(getConfigurationContext(newBase));}private static Context getConfigurationContext(Context context) {Configuration configuration = context.getResources().getConfiguration();configuration.fontScale = 1;return context.createConfigurationContext(configuration);}
BaseActivity 完整代码
package com.example.fontscaleimmutabledemojava;import android.content.Context;import android.content.res.Configuration;import androidx.appcompat.app.AppCompatActivity;/*** 所有Activity的基类** @author songguanxun* @date /10/21*/public class BaseActivity extends AppCompatActivity {@Overrideprotected void attachBaseContext(Context newBase) {super.attachBaseContext(getConfigurationContext(newBase));}private static Context getConfigurationContext(Context context) {Configuration configuration = context.getResources().getConfiguration();configuration.fontScale = 1;return context.createConfigurationContext(configuration);}}
不推荐方法
Activity 中重写 getResources()
此方法是不符合逻辑的。
getResources() 方法,会在页面获取资源时多次调用,比如用手点一下页面任意位置,就会调用此函数。在此处修改配置是不符合逻辑的。
@Overridepublic Resources getResources() {Resources resources = super.getResources();Configuration configuration = resources.getConfiguration();// 设置字体大小不随系统设置变化。字体大小(字体比例)始终设置为默认值if (configuration.fontScale != 1) { // 字体大小(字体比例)为非默认值configuration.fontScale = 1; // 字体大小(字体比例)设置为默认值resources.updateConfiguration(configuration, resources.getDisplayMetrics());}return resources;}
进入页面时,getResources() 方法调用的日志
调用Resources.updateConfiguration()
此方法已废弃,不应再使用。
错误方法
将布局中textSize的字号单位sp,换成dp。这种方式是完全错误的。
sp 是字号单位,在 textSize 中使用其他类型的单位,Android Studio 是有Warning警告的。
另外,将 sp 改为 dp,需要将所有用到 textSize 的控件全部进行修改,明显不合理。
如下是安卓官方文档中对 “尺寸” 的说明。
更多资源类型 | Android 开发者 | Android Developers ()
参考
Configuration | Android Developers ()