屏幕适配笔记

176 阅读6分钟
# val displayMetrics = applicationContext.resources.displayMetrics
# Log.e("TAG", "densityDpi: " + displayMetrics.densityDpi)
# Log.e("TAG", "density: " + displayMetrics.density)
# Log.e("TAG", "widthPixels: " + displayMetrics.widthPixels)
# Log.e("TAG", "heightPixels: " + displayMetrics.heightPixels)
# //todo 联想
# //17:06:01.022  E  densityDpi: 400
# //17:06:01.022  E  density: 2.5     (其实就是400dpi/160=2.5)
# //17:06:01.022  E  widthPixels: 1600
# //17:06:01.022  E  heightPixels: 2530
# //红米note pro
# //17:06:01.022  E  densityDpi: 440
# //17:06:01.022  E  density: 2.75  (其实就是440dpi/160=2.75)
# //17:06:01.022  E  widthPixels: 1080
# //17:06:01.022  E  heightPixels: 2276
# //todo 从中就可以提取出几点信息:
# //     1.屏幕像素密度为 400 dpi
# //     2.density 等于 2.5,说明在该设备上 1 dp 等于 2.5 px
# //     3.px = dp * (dpi / 160)
# //     联想:宽dp = 1600px / (400dpi/160) = 640dp   高dp = 2530px / (400dpi/160) = 1012dp
# //     红米:宽dp = 1080px / (440dpi/160) = 392dp   高dp = 2276px / (440dpi/160) = 827dp
# //    如果系统根据当前设备屏幕的 最小宽度 (smallestWidth) 没找到对应的 values-sw<N>dp 文件夹,
# //    则会去寻找与之 最小宽度 (smallestWidth) 相近的 values-sw<N>dp 文件夹,
# //    系统只会寻找小于或等于当前设备 最小宽度 (smallestWidth) 的 values-sw<N>dp,这就是优于 宽高限定符屏幕适配方案 的容错率,
# //    并且也可以少生成很多 values-sw<N>dp 文件夹,减轻 App 的体积。
# // todo
# //  Android 系统定义的屏幕像素密度基准值是 160 dpi,该基准值下 1 dp 就等于 1 px,
# //  依此类推 400 dpi 下 1 dp 就等于 2.5 px,计算公式:
# //   px = dp * (dpi / 160)
# 
# //举个例子。假设设计师给出来的设计稿是按照 1080 x 1920 px,420 dpi 的标准来进行设计的,
# // 那么设计稿的宽高即 411 x 731 dp,那对于一个希望占据屏幕一半宽度的 ImageView 来说,在设计稿中的宽即 205.5 dp
# //根据公式可得到对应的dp尺寸为。
# //   1080px / (420dpi / 160) =411dp(宽)
# //   1920px / (420dpi / 160) =731dp(高)
# 
# //那么,对于一台 1440 x 2880 px,560 dpi 的真机来说,其宽高即 411 x 822 dp,
# //此时我们在布局文件中就可以直接使用设计稿中给出来的宽度值,使得 ImageView 在这台真机上也占据了屏幕一半宽度。
# //虽然设计稿和真机的屏幕像素并不相同,但由于屏幕像素密度的存在,使得两者的 dp 宽度是一样的,从而令开发者可以只使用同一套 dp 尺寸值就完成设计要求了
# 
# //既然有了 dp,那我们为什么还需要进行屏幕适配呢?
# //当然也是因为 dp 只适用于大部分正常情况了。以上情况之所以能够完美适配,
# //那也是因为举的例子刚好也是完美的:1440/1080=560/420=1.3333,
# //设计稿和真机的 px 宽度和 dp 宽度刚好具有相同比例,此时使用 dp 才能刚好适用
# 
# //再来看一个不怎么完美的例子。以两台真机为例:
# //华为 nova5:1080 x 2259 px,480 dpi,屏幕宽度为 1080 / (480 / 160) = 360 dp
# //三星 Galaxy S10:1080 x 2137 px,420 dpi,屏幕宽度为 1080 / (420 / 160) = 411 dp
# 
# //可以看到,在像素宽度相同的情况下,不同手机的像素密度是有可能不一样的。
# //手机厂家有可能是根据屏幕像素和屏幕尺寸来共同决定该值的大小,但不管怎样,这就造成了应用的实际效果与设计稿之间无法对应的情况:
# //对于一个 180 dp 宽度的 View 来说,在华为 nova5 上能占据一半的屏幕宽度,
# //但在三星 Galaxy S10 上却只有 180 / 411 = 0.43,这就造成了一定偏差
# 
# //以上情况就是直接使用 dp 值无法解决的问题,使用 dp 只能适配大部分宽高比例比较常规的机型,对于特殊机型就无能为力了……
# //屏幕适配就是要来解决上述问题。对于屏幕适配,开发者希望实现的效果主要有两个:
# 
# //1.在声明宽高值时,能够直接套用设计稿上给出来的尺寸值,这个尺寸值映射到项目中可能是对应一个具体的值,
# //也可能是对应多套 dimens 文件中的值,但不管是哪一种,在开发阶段都希望能够直接套用而无需再来进行手动计算。这关乎进行屏幕适配的效率
# 
# //2.适配后的界面最终在不同屏幕上的空间比例都能保持一致。这关乎进行屏幕适配的最终成效
# 
# //todo smallestWidth
# //  smallestWidth 也是系统原生支持的一种适配方案。smallestWidth 即最小宽度,
# //  指的是[最短的]那一个边长,而不考虑屏幕的方向,适配原理和宽高限定符方案一样,
# //  本质上都是通过比例换算来为不同尺寸的屏幕分别准备一套 dimens 文件,应用在运行时再去引用相匹配的 dimens 文件,以此来实现屏幕适配
# 
# //首先,我们要以设计稿的尺寸作为基准分辨率,
# //假设设计师给出来的设计稿是按照 **1080 x 1920 px **的标准来进行设计的,那么基准分辨率就是设计稿的宽度 1080 px
# //先为宽度为 360 dp 的设备生成 dimens 文件,生成规则:
# //将 360 dp 均分为 1080 份,每份 360 / 1080 dp,声明 1080 个 key 值,值从 360 / 1080 dp 开始递增,每次递增 360 / 1080 dp
# //类似地,我们再按照上述规则为宽度为 380 dp 的设备生成 dimens 文件:
# //最终,为市面上主流的屏幕宽度均按照如上规则生成一套专属的 dimens 文件,每套文件均放到以宽度进行命名的 value 文件夹内,就像以下这样:
# //values
# //values-sw360dp
# //values-sw380dp
# //values-sw400dp
# //values-sw420dp
# //smallestWidth 方案和宽高限定符方案最大的差别就在于容错率,
# // smallestWidth 方案具有很高的容错率,即使应用中没有找到符合当前屏幕宽度的 dimens 文件,
# // 应用也会向下寻找并采用最接近当前屏幕宽度的 dimens 文件,
# // 只有都找不到时才会去引用默认的 dimens 文件。
# // 只要我们准备的 dimens 足够多,且每套 dimens 文件以 5 ~ 10 dp 作为步长递增,
# // 那么就能够很好地满足市面上的绝大部分手机了。
# // 此外,我们不仅可以使用设计稿的 px 宽度作为基准分辨率,也可以改为使用 dp 宽度,计算规则还是保持一致
# ```
# ```
# 参考: https://juejin.cn/post/6999445137491230728