搞Android已经有一段时间了,Android设备的分辨率适配一直是一个头疼的问题,正好前一段时间,组内大佬让我搞一个屏幕适配的方案,来搞定这个问题,正好趁着这个机会总结一下。
首先要确定几个概念
android中的dp在渲染前会将dp转为px,计算公式:
- px = density * dp;
- density = dpi / 160;
- px = dp * (dpi / 160);
1.px:我们通常所说的像素,例如设计给出的设计稿是 1334 * 750的
2.density:屏幕密度,等于dpi/160
3.dp:也就是dip,表示独立像素,是根据px和dpi来决定的,px = dp * (dpi / 160)
4.dpi:dpi是根据屏幕真实的分辨率和尺寸来计算的,每个设备都可能不一样。
举个例子:屏幕分辨率为:1920*1080,屏幕尺寸为5吋的话,那么dpi为440。
为什么会出现屏幕分辨率的问题呢?
假设我们UI设计图是按屏幕宽度为360dp来设计的,那么在上述设备上,屏幕宽度其实为1080/(440/160)=392.7dp,也就是屏幕是比设计图要宽的。这种情况下, 即使使用dp也是无法在不同设备上显示为同样效果的。 同时还存在部分设备屏幕宽度不足360dp,这时就会导致按360dp宽度来开发实际显示不全的情况。
而且上述屏幕尺寸、分辨率和像素密度的关系,很多设备并没有按此规则来实现, 因此dpi的值非常乱,没有规律可循,从而导致使用dp适配效果差强人意。
适配方法:smallestWidth适配
smallestWidth适配,或者叫sw限定符适配。指的是Android会识别屏幕可用高度和宽度的最小尺寸的dp值(其实就是手机的宽度值),然后根据识别到的结果去资源文件中寻找对应限定符的文件夹下的资源文件。
举个例子,Redmi note 3 的dpi是480,横向像素是1080px,根据px=dp(dpi/160),横向的dp值是1080/(480/160),也就是360dp,系统就会去寻找是否存在value-sw360dp的文件夹以及对应的资源文件。
smallestWidth限定符适配有很好的容错机制,如果没有value-sw360dp文件夹,系统会向下寻找,比如离360dp最近的只有value-sw350dp,那么Android就会选择value-sw350dp文件夹下面的资源文件。
我们还有以375px宽度的设计稿为例,在values-sw360dp文件夹下的dimens文件应该怎么编写呢?
这个文件夹下,意味着手机的最小宽度的dp值是360,我们把360dp等分成375等份,每一个设计稿中的像素,大概代表smallestWidth值为360dp的手机中的0.96dp,那么接下来的事情就很简单了。如果我们的设计稿里面有一个大小为355px * 268px 的textview那么我们在代码中就可以直接设置,如下图
是不是很简单的使用。
这些生成dimens文件的方法已经有大神给出了解决方法,点击这个链接可以根据提示生成dimens文件。giutbug链接
总结
最后总结一下这个方案的思想。当前设备总宽度 (单位为 dp)/ 设计图总宽度 (至于是 dp 还是 px 都不重要) = value (设计图上每个单位占当前设备多少 dp)
然后根据这个 value 算出对应资源文件的 dimens,然后在项目中引用 dimens,系统会选择最合适的宽度的资源文件下的 dimens。