android屏幕适配问题分析及各种解决方案优缺点分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cui130/article/details/84777908

在这里插入图片描述

从事android开发已有5年之久,项目中遇到的屏幕适配的问题也有n次了,可是有一个很奇怪也很让人头疼的现象让从事多年开发的我很不爽。什么问题呢,就是“适配虐我千万遍,我见适配如初见”,真是想说一句fuck,这次我终于坚决的征服掉了她,下面就来具体讲解征服她的全过程,一定要有决心,耐着性子慢慢看。

  本着不重复造轮子的理念,对现有适配方案统统拿来细细研读了一番,得出的结论是已基本可以解决适配问题,但是如果你去百度可以发现有不止一种解决方案,这些方案哪一个更好呢,听我来慢慢分析。(客官莫急,要知道心急吃不到“热豆腐”)。

参考

首先,为了节约用纸,涉及到的一些基础知识就不在这里赘述了,留下传送门方便小白穿越:
android UI设计图片和文字尺寸px对应dp、sp值换算
Android 屏幕适配:最全面的解决方案

下面是现有各种方案总结比较好的文章:

  1. px适配法:
    Android屏幕适配dp、px两套解决办法
  2. dp适配法:
    Android屏幕适配之dp分包法
    Android dp方式的屏幕适配-原理(后期补充完整讲解)
  3. 百分比适配法:
    Android 屏幕适配方案
    Android 百分比布局库(percent-support-lib) 解析与扩展
  4. 单位转换法:
    一行代码搞定安卓全屏幕适配

适配问题由来

为了方便阅读本文,还是啰嗦补充几个基础要点,以免“仁者见仁”:

  1. dp/dip:密度无关像素,1dp=1/160 inch 看公式就可以理解。
  2. dpi :像素密度,即每英寸内像素数

从上面dp的公式可以看出官方提供的dp单位只是像素无关 但是和尺寸很有关,所以dp无法适配差别较大的尺寸屏幕,这也就是屏幕适配问题的由来。

各方案简析

首先要普及一个概念叫“最小宽度限定符”,系统可以识别这些限定符来匹配相对应的屏幕尺寸所需要的资源文件,最常用的例子就是mipmap-xdpi作为图片资源的限定,那其实所有res的资源都有对应的限定符,比如layout布局文件有layout-large限定符来匹配大屏,values也有类似的限定符供app运行时选取。

方案一:px适配法原理
  以某一分辨率(比如480*320)的 宽度 为基准,其他分辨率按宽度等比例缩放(高度由于习惯滑动,所以采用宽度为基准),在values文件的dimens文件中定义x1=1px…x320=320px。如果UI设计师是在宽度为640px的屏幕上做的标注,那么1px在xml中引用资源变量为x0.5,也就是要用小数来表示了,所以采用较大宽度的分辨率作为基准比较合适,推荐使用1080作为基准。
  基准值选好后以此生成其他各分辨率对应的资源文件,理论上是生成的文件越多适配误差越小,但是受限于安装包大小一般选取主流分辨率适配。

方案二:dp适配法原理
  这种方案原理和px适配法是一样的,只是“最小宽度限定符”的单位不同罢了。用dp作为限定符的好处是可以减少适配资源文件的数量。这里有一个容易误解的点dp作为限定符来区分不同宽度的屏幕,在计算比例时容易理解为dp总值的比例,例如360dp和480dp的换算比例易误解为480/360=1.5,其实不是这样子的。比例的结果还是要将宽度换算为px的出。具体dp到px转换可以参考上文传送门的基础篇,比较详细。

方案三:百分比适配法原理
  这个方案也是和px适配法同样的原理,百分比顾名思义只需要在px基础上除以总宽度即可。而且现在也不需要再去手写了,官方已经给出兼容包提供百分比布局:PercentRelativeLayout、PercentFrameLayout,线性布局的百分比布局没有给出可在参考链接中鸿神的文章里查看到亲手仿制的。

方案四:单位转换法原理
  此种方案的原理比较简单粗暴,系统进行长度计算的接口为TypedValue中的applyDimension函数,传入单位与value将其计算为对应的px数值:

public static float applyDimension(int unit, float value,DisplayMetrics metrics){
      switch (unit) {
          case COMPLEX_UNIT_PX:
          return value;
          case COMPLEX_UNIT_DIP:
          return value * metrics.density;
          case COMPLEX_UNIT_SP:
          return value * metrics.scaledDensity;
          case COMPLEX_UNIT_PT:
          return value * metrics.xdpi * (1.0f/72);
          case COMPLEX_UNIT_IN:
          return value * metrics.xdpi;
          case COMPLEX_UNIT_MM:
          return value * metrics.xdpi * (1.0f/25.4f);
      }
	return 0;
}
  1. 可以看见换算方法非常简单,而DisplayMetrics的所有属性都是public的,不用反射就能修改;
  2. pt的原意是长度单位磅,根据当前屏幕与设计图尺寸将metrics.xdpi进行修改就可以实现将pt这个单位重定义成我们所需要的相对长度单位,使修改之后计算出的1pt实际对应的px/屏幕宽度px=1px/设计图宽度px。
  3. 而这个DisplayMetrics从哪来?从源码中可以看出一般为mContext.getResources().getDisplayMetrics(),这个mContext即为所在Activity;
  4. Activity中所拿到的DisplayMetrics与Application中拿到的DisplayMetrics虽然不是一个实例,但是所有数值都相同,在Application中进行更改也会影响到所有Activity中;
  5. Configuration的变化会导致DisplayMetrics的重新计算还原,需要handle;
  6. px,dp与sp都是平时常用的单位,而pt,in与mm几乎没有看见过,从这些不常见的单位下手正好可以不影响其他常用的单位。

各方案优缺点分析

方案一

  1. 由于分辨率碎片化过于严重,想要高度适配市场机型需要很多很多的适配文件,造成打包文件过大。
  2. 新机春笋般发展,几乎不可能覆盖所有机型。

方案二

  1. 相较方案一适配资源文件减少一些,但依然不少。
  2. 同样不能覆盖所有机型,但是对新机型的适配率高很多。

方案三

  1. 省去了这些资源文件,增加了一个依赖包,不过内存占用量肯定是少了很多。
  2. 可以覆盖所有机型。
  3. 使用不太方便,尤其在嵌套比较多的布局里。因为UI给的图标注全是px,每个细小的标准都要自己计算成百分比也是不小的工作量,而且UI有的时候不会把状态栏、标题栏、虚拟按键考虑进去,最后运行出来的效果可能和设计效果图有一定差距。

方案四

  1. 不占内存。
  2. 可以覆盖所有机型。
  3. 修改系统单位pt,虽然这个单位很冷门,但是既然存在肯定还是有使用的地方,可能会造成一些无法预知的问题。

以上四种方案在布局预览时都需要使用和UI设计同样的尺寸。

总结

综合以上分析方案二相较方案一适配性更好优先选择,方案三在简单布局上优势较为明显,方案四不稳定因素较多。

最后,感谢看到这里的同学,有哪里觉得不理解或者感觉不对的地方欢迎评论留言,会尽快回复。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/cui130/article/details/84777908