App字体大小不变
如果用户将系统字体大小设置的非常大,可能导致APP的文字大小显示异常。
目标效果是,APP内字体大小不随系统设置的 字体大小 变化。
系统的字体大小设置为 超大 时:(字体大小 可变)
系统的字体大小设置为 超大 时:(字体大小 不变)
Android/FontScale · 宋冠巡/示例 - 码云 - 开源中国 (gitee.com)
Android/FontScaleJava · 宋冠巡/示例 - 码云 - 开源中国 (gitee.com)
Android/FontScaleCompose · 宋冠巡/示例 - 码云 - 开源中国 (gitee.com)
在 Activity 初始化 Context 时,将 字体缩放比例(fontScale)始终设置为 1 。
在基类 BaseActivity 中,重写 attachBaseContext() 方法,设置 Configuration.fontScale = 1f
android:configChanges:指定Activity将自行处理的一个或多个配置更改。如果未指定,则如果系统中发生任何这些配置更改,将重新启动Activity 。
当 configChanges 设置为 fontScale 后,后台App重新进入前台时,Activity将不会重启,而是触发 onConfigurationChanged 后直接从后台进入前台。
请注意,本方法不适用于 Compose 项目。
Compose项目字体大小不变的办法,请参考后面的《Compose实现》章节。
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
overrideFontScale(newBase)
}
/**
* 重置配置 fontScale:保持字体比例不变,始终为 1.
*/
private fun overrideFontScale(context: Context?) {
if (context == null) return
context.resources.configuration.let {
it.fontScale = 1f // 保持字体比例不变,始终为 1.
applyOverrideConfiguration(it) // 应用新的配置
}
}
applyOverrideConfiguration()方法只能被调用一次,且必须在 getResources() 和 getAssets() 前调用。
package com.example.fontscale
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
/**
* 所有Activity的基类
*/
open class BaseActivity : AppCompatActivity() {
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
overrideFontScale(newBase)
}
/**
* 重置配置 fontScale:保持字体比例不变,始终为 1.
*/
private fun overrideFontScale(context: Context?) {
if (context == null) return
context.resources.configuration.let {
it.fontScale = 1f // 保持字体比例不变,始终为 1.
applyOverrideConfiguration(it) // 应用新的配置
}
}
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
overrideFontScale(newBase);
}
/**
* 重置配置 fontScale:保持字体比例不变,始终为 1.
*/
private void overrideFontScale(Context context) {
if (context == null) return;
Configuration configuration = context.getResources().getConfiguration();
configuration.fontScale = 1f;
applyOverrideConfiguration(configuration);
}
package com.example.fontscalejava;
import android.content.Context;
import android.content.res.Configuration;
import androidx.appcompat.app.AppCompatActivity;
/**
* 所有Activity的基类
*/
public class BaseActivity extends AppCompatActivity {
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(newBase);
overrideFontScale(newBase);
}
/**
* 重置配置 fontScale:保持字体比例不变,始终为 1.
*/
private void overrideFontScale(Context context) {
if (context == null) return;
Configuration configuration = context.getResources().getConfiguration();
configuration.fontScale = 1f;
applyOverrideConfiguration(configuration);
}
}
Compose项目,经过测试,在 attachBaseContext 中,applyOverrideConfiguration 无效;
并且,如果设置了 android:configChanges,也需要在 onConfigurationChanged 重新配置 fontScale。否则,字体大小配置修改后,当后台App重新进入前台时,Activity将不会重启,而是直接从后台进入前台,页面字体将直接变成 超大。
在 attachBaseContext 和 onConfigurationChanged 中,设置 getResource().getConfiguration().fontScale 的值始终为 1.
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
setFontScale()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// 如果 Activity 配置了 android:configChanges 属性,则对应的系统设置修改后,将进入此函数,不再重启 Activity
setFontScale()
}
/**
* 保持字体比例不变,始终为 1.
*/
private fun setFontScale() {
resources.configuration.fontScale = 1f
}
package com.example.fontscalecompose
import android.content.Context
import android.content.res.Configuration
import androidx.activity.ComponentActivity
/**
* 所有Activity的基类
*/
open class BaseActivity : ComponentActivity() {
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
setFontScale()
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
// 如果 Activity 配置了 android:configChanges 属性,则对应的系统设置修改后,将进入此函数,不再重启 Activity
setFontScale()
}
/**
* 保持字体比例不变,始终为 1.
*/
private fun setFontScale() {
resources.configuration.fontScale = 1f
}
}
android:configChanges 配置方法,参考如下博客
Activity生命周期_宋冠巡的博客-CSDN博客
在Activity中重写 getResources(),此方法是不符合逻辑的,且可能造成性能问题。
getResources() 方法,会在页面获取资源时多次调用,而不是在页面初始化时调用一次。所以,在此处修改配置是不符合逻辑的。
另外,如果页面布局比较复杂,调用 getResources() 的次数就会非常多,在getResources()方法内耗费时间更新Configuration,可能会 造成卡顿 。
@Override
public Resources getResources() {
Resources resources = super.getResources();
Configuration configuration = resources.getConfiguration();
// 设置字体大小不随系统设置变化。字体大小(字体比例)始终设置为默认值
if (configuration.fontScale != 1) { // 字体大小(字体比例)为非默认值
configuration.fontScale = 1; // 字体大小(字体比例)设置为默认值
resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}
return resources;
}
此方法已废弃,不应再使用。
将布局文件中 android:textSize 属性的字号单位 sp 换成 dp。这种方式是 错误的 。
尺寸的官方文档
Configuration | Android Developers (google.cn)
Activity | Android Developers (google.cn)
ContextThemeWrapper | Android Developers (google.cn)
Context | Android Developers (google.cn)