Android 屏幕适配
dp 直接适配
dp 是什么?
dp 指的是设备独立像素,以 dp 为尺寸单位的控件,在不同分辨率和尺寸的手机上代表了不同的真实像素。
px = dp * (dpi / 160)
dpi 是什么?
dpi 是像素密度,指的是在系统软件上指定的单位尺寸的像素数量,它往往是写在系统出厂配置文件的一个固定值。
我为什么要强调它是软件系统上的概念?因为大家买手机的时候,往往会听到另一个叫 ppi 的参数,这个在手机屏幕终止的也是像素密度,但是这个是物理上的概念,它是客观存在的不会改变。dpi 是软件参考了物理像素密度后,人为指定的一个值,这样保证了某一个区间内的物理像素密度在软件上使用同一个值。这样有利于我们的 UI 适配。
比如,几部相同分辨率不同尺寸的手机的 ppi 可能分别是 430、440、450,那么在 Android 系统中,可能 dpi 会全部指定为 480,这样的话 dpi / 160 就会是一个相对固定的值,这样就能保证相同分辨率下不同尺寸的手机表现一致。
查看设备 dpi:ro.sf.lcd_density=160
1
2
3 adb shell
cat system/build.prop
问题
而在不同分辨率下,dpi 将会不同,比如
… | 1080*720 | 1920*1080 |
---|---|---|
dpi | 320 | 480 |
dpi / 160 | 2 | 3 |
根据上面的表格,720P 和 1080P 的手机,dpi 是不同的,这也就意味着,不同的分辨率中,1dp 对应不同数量的 px,这也就是,当我们使用 dp 来定义一个控件大小的时候,在不同手机里会表现出相应大小的像素值。
可以说,通过 dp 加上自适应布局和 weight 比例布局可以基本解决不同手机上的适配问题,这基本是最原始的 Android 适配方案。
这种方式存在两个小问题:
- 只能保证适配绝大部分手机,部分手机仍然需要单独适配。因为并不是所有的 1080P 的手机 dpi 都是 480,比如 Google 的 Pixel2 (1920 * 1080)
- 无法快速高效的吧设计师的设计稿实现到布局代码中,通过 dp 直接适配,我们只能让 UI 基本适配不同的手机,但是在设计图和 UI 代码之间的鸿沟,dp 是无法解决的,因为 dp 不是真实像素。在把设计稿向 UI 代码转换的过程中,我们需要耗费相当的精力去转换尺寸,这会极大的降低我们的生产力,拉低开发效率。
宽高限定符适配
简单说,及时穷举市面上所有的 Android 手机的宽高像素值
设定一个基准的分辨率,其他分辨率都根据这个基准分辨率来计算,在不同的尺寸文件夹内部,根据该尺寸编写对应的 dimens 文件。
比如以 480 × 320 为基准分辨率
- 宽度为 320,将任何分辨率的宽度整分为 320 份,取值为 x1 ~ x320
- 高度为 480,将任何分辨率的高度整分为 480 份,取值为 y1 ~ y480
那么对于 800 * 480 分辨率的 dimens 文件来说,
- x1 = (480 / 320) * 1 = 1.5px
- x2 = (480 / 320) * 2 = 3px
- …
这个时候,如果我们的 UI 设计界面使用的就是基准分辨率,那么我们就可以按照设计稿上的尺寸填写相对应的 dimens 引用了,而当 APP 运行在不同分辨率的手机时,这些系统会根据这些 dimens 引用去该分辨率的文件夹下寻找对应的值。这样基本解决了我们的适配问题,而且极大地提高了我们 UI 开发的效率。
问题
需要精准命中才能适配,否则就只能用统一的默认的 dimens 文件了。容错机制较差。
UI 适配框架
smallestWidth 适配
或者叫做 sw 限定符适配。指的是 Android 会识别屏幕可用高度和宽度的最小尺寸的 dp 值(其实就是手机的宽度值),然后根据识别到的结果去资源文件中寻找对应的限定符的文件夹下的资源文件。
这种机制和上文提到的宽高限定符适配原理是一样的,都是系统通过特定的规则来选择对应的文件。
举个例子,小米 5 的 dpi 是480,横向像素是 1080 px,根据 px = dp(dpi / 160),横向的 dp 值是 360 dp,系统会去寻找是否存在 value-sw360dp 的文件夹以及对应的资源文件。
smallestWidth 限定符和宽高限定符适配最大的区别在于,前者有很好的容错机制,如果没有 value-sw360dp 文件夹,系统会向下寻找,比如离 360dp 最近的只有 value-sw350dp,那么 Android 就会选择此文件夹下面的资源文件。这个特性就完美的解决了上文提到的宽高限定符的容错问题。
最低支持版本 4.0 了;多个 dimens 文件可能导致 apk 变大