Android修炼系列(二十),由系统字号来调整 App 字体大小

您所在的位置:网站首页 安卓默认字体大小 Android修炼系列(二十),由系统字号来调整 App 字体大小

Android修炼系列(二十),由系统字号来调整 App 字体大小

2024-04-17 11:40| 来源: 网络整理| 查看: 265

在平时开发中,一般 App 的界面布局都只会适配标准字体的尺寸,如果用户在设置中修改了系统字号大小,那么 App 的 UI 就有可能惨不忍睹。

针对这种情况,很多 App 都会选择放弃使用系统字号,方法也很简单,直接在我们的 BaseActivity 中修改 fontScale:

@TargetApi(17) override fun getResources(): Resources { val resources = super.getResources(); val configContext = createConfigurationContext(resources.configuration) return configContext.resources.apply { configuration.fontScale = 1.0f displayMetrics.scaledDensity = displayMetrics.density * configuration.fontScale } }

在低版本中,我们还能这样设置,实测没啥问题,不过 updateConfiguration 方法已经处于废弃状态:

override fun getResources(): Resources { return super.getResources().apply { configuration.fontScale = 1.0f updateConfiguration(configuration, displayMetrics) } } sp 转 dp

将 sp 改为 dp 也可以保持字体缩放不变。

顺便说一嘴,标注尺寸时,sp 与dp 关系:字体标准100%时 1sp=1dp,而字体标准大于100%时,1sp 就会大于 1dp。

bbb.png

sp:与缩放无关的抽象像素,sp 与 dp 一样是物理像素,但 Android 系统允许用户自定义文字尺寸大小,因此 sp 能根据系统设置而呈现出不同效果,这也许就是规范里,文字尺寸要使用 sp 的原因吧。

而 dp:设备独立像素,它只与设备屏幕有关,所以 dp 标注的文字就不会随着系统字号的变化而变化了。但这样也会产生一个问题,如果 App 自身没有内置字号调整功能,又不受系统字号影响,那么对于部分用户群体来说,是非常不友好的。

字号缩放

通过上面的介绍,字号调整功能呼之欲出了,我们可以修改 configuration.fontScale 的值来定义字号的缩放倍数。

代码就不贴了,运行了下是 ok 的。但是这样会产生一些问题:

如果文字控件没有自适应高度,就会导致文字显示不全;

fontScale 只能修改字体大小,其他 UI 元素不能跟随改变,这点就很难接受了,因为设完后你会发现整个 UI 都变得不协调了。

针对这种情况,另一种很巧妙的方案就应势而生了。

修改 density

dpi(每英寸的点数): 像素密度,是屏幕单位面积内的像素数。它与分辨率不同,分辨率是屏幕上的总像素数。

density: 当前像素密度指定将 dp 单位转换为像素时所必须使用的缩放系数,density = dpi/160,并且 px = dp * density。

有些抽象吧,再多说一嘴,我们都知道,android 支持不同的像素密度 dpi 模式,具体见下:

888.png

举个栗子,由上面定义可知,在 hdpi 模式下:1dp=1.5px,也就是说设计师在 PS 里定义一个view 高 72px,开发就应该定义该 view 高 48dp,Photoshop 中 21px 大的字体,开发会定义为 14sp(标准字体下,sp=dp)。

所以想一想,在 hdpi 模式下,假设我的 viewHeight=1dp,现在我不想 1dp=1.5px 了,我想 1dp=1.75px 了,是不是等比例放大 dpi 和 density 就可以了呢?这样界面的 UI 元素是不是也就等比例适配了呢。BaseActivity 代码见下:

private fun setDensity() { val systemMetrics = getSystemMetrics() val scale = 1.0f // 根据需求定义系数 with(resources.displayMetrics) { density = systemMetrics.density * scale scaledDensity = systemMetrics.density * scale densityDpi = (systemMetrics.densityDpi * scale).toInt() } } private fun getSystemMetrics(): DisplayMetrics { return applicationContext.resources.displayMetrics; }

这里的 scaledDensity 需要注意,是将 fontScale=1 情况处理了,以适配 sp,当调整系统字体大小时 scaledDensity 实际值见下:

/* 标准字体时,fontScale=1,非标准时,fontScale!=1 */ displayMetrics.scaledDensity = displayMetrics.density * configuration.fontScale

好了,到这里思路基本完了,代码虽然简单,但这个思想涉及到的细节还是值得琢磨的, gitHub 示例。

问题

使用这个方案后,经过测试,还是有几点需要注意适配的:

页面宽高适配:当页面整体 UI 元素都放大后,会存在当前页面存放不下全部元素了的情况,这个时候就需要添加 Scroll 滚动效果了;横向的话,可根据需要,显示不够“..”。

部分元素不缩放:如果在当前页面,我想部分元素保持原始大小,不进行缩放呢?如上面所说的横向显示不够".."情况,如果这个文本是很重要的,使用“..”显然是不合适的。这时,我们可以获取元素原始大小,再动态设置:

open fun dip2px(context: Context, dpValue: Float): Int { val scale = context.applicationContext.resources.displayMetrics.density return (dpValue * scale + 0.5f).toInt() }

本文到这里就结束了,希望对你有帮助。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3