Android屏幕适配全面分析

本文适合对屏幕适配有一定了解的读者,试图尽可能全面的阐释出Android屏幕适配问题的本质和解决方案,对实现细节描述可能不够详细,感兴趣的同学可自行查阅相关资料。第一次发文,欢迎大家批评指正。

主要问题

Android设备差异化非常大,分辨率不同、屏幕尺寸不同、屏幕长宽比也不同。

分辨率方面,目前主流标准分辨率有720p、1080p、2k、4k等,根据移动观象台数据显示,2016年4季度,安卓设备前五名分辨率占比75%,前十名占比88%,但排名第100名的分辨率也占到0.01%,这一数据不一定精确,但反映了分辨率“千差万别,主流集中”的特点,另外有部分手机内置虚拟按键(如华为),会导致屏幕可用分辨率发生变化。

屏幕尺寸方面,可分为穿戴设备、手机、平板和电视等,穿戴设备和电视一般是针对特定硬件开发,我涉及的也不多,这里不讨论,手机的特点是屏幕大小基本与手掌相当,目前一般集中在5-5.5寸,而平板则屏幕大小相差较大,一般7-11寸。

屏幕长宽比不同,这个与分辨率的多样性是相关的,有4:3,16:9等,不过这个差异一般不是太明显,就拿电视来说,从以前的方形电视,到目前主流偏宽的电视,都是可以观看的,可能稍有拉伸。

上面提到的三个问题,先说第三个问题,比如适配一个按钮控件,适配时首先要保证按钮在不同手机上宽度占屏幕比例一致,但高度的控制就有两种方案了:一种是保证按钮的高度占屏幕的比例一致,如果在两个长宽比不同的设备上显示,这两个按钮的长宽比就不一致了;另一种方案是保持按钮的长宽比,但如果页面不可滚动,按钮的高度占屏幕比例就发生变化了。不同场景下,需求可能会发生变化,最好的解决办法是根据需求分别处理,如处理图片时保持宽高比固定,处理不可滚动页面上控件时,保持高度占屏幕比例固定,但这样就太麻烦了,而且一般情况下设备的宽高比还是比较相似的,因此一般情况下我们随便选择其中一种方案即可,后文我们不再讨论这一问题。

前两个问题与Android中的度量单位有关,Android中的度量单位有px(像素)和dp(像素无关尺寸,可近似理解成物理尺寸),字体单位有px和sp(也是像素无关尺寸,还与系统设置有关),官方推荐使用dp和sp。但这也不能完全解决屏幕适配问题,后面再继续分析。

还有一个要说明的问题是屏幕上显示的内容有哪些我们要适配,如果一个控件的宽度刚好为父容器宽度,或控件宽度刚好与父容器一样大,或两个按钮平分父容器宽度,那么我们可以使用match-parent、wrap-content和线性布局中的weight进行设置,不需要任何适配,他们在各种设备中显示会一致。因此我们在适配时一般禁用绝对布局,使用上述几种方式做相对适配,有时还会增加嵌套层数来使用这些相对适配方式,目的就是便于适配。但上面这些还是不能解决所有问题,比如我们一般都需要设置padding和margin,在复杂布局中把控件设置成宽度占屏幕宽度60%一般都会写绝对数等。

总结上面这些分析,我们需要处理的就是一些相对适配无法处理的问题,在不同分辨率或不同屏幕大小的设备上尽量保持控件的占屏幕比例一致。

解决方案

1.      dp适配

这个特别推荐用来做单纯的手机适配。前面提到手机的屏幕大小相对固定,即屏幕长宽的dp是固定的,那么直接在布局里写dp,就能保证显示效果基本一致。当然由于手机屏幕大小还是稍微有些差异,而且dp与屏幕物理尺寸之比不是定值(但几乎一致),因此不能100%精确适配,但一般的适配是没有问题的。

说完手机,还有平板,由于平板比手机大很多,可显示更多内容,因此一般的应用会为平板开发独立应用,或使用独立布局。这里我们单独考虑平板的适配问题,平板适配时,分辨率和dp都会变动,没有一个基准固定值,我们就只能做自适应了,即在不同设备上自动设置成不同值。可以创建不同values-限定符的文件夹,通过dimens文件的配置方式实现,限定符主要包括DPI限定符、分辨率限定符和dp限定符。也可以在代码中计算并动态设置,还可以使用百分比布局库等。下面逐个分析:

2.      DPI限定符适配

DPI指一英寸的点(屏幕上即为像素)个数,由屏幕尺寸和分辨率可计算得出,px = dp * (dpi / 160)对于手机而言,整个屏幕的px是定值,dpi是屏幕的硬件决定的,一般不可改变,这样就能保证使用dp单位时,显示的效果就是物理尺寸。然而手机在计算像素时,用的并不是设备的实际DPI,而是手机厂商配置的DPI(定义在 /system/build.prop 中),明明手机的实际DPI是300,它可以配置成320,这就导致使用dp单位时,有可能在不同设备上显示的物理尺寸有差异,但一般手机不会随便改这个DPI配置的,它只会影响我们使用dp单位时的显示大小,为什么不用标准配置让控件显示正常大小呢?乱改对设备厂商没什么好处,所以他们最多会微调。这就是前面说到的dp与屏幕物理尺寸之比不是定值的问题。

现在我们假定手机配置的DPI都是实际DPI,来进行后面的分析。DPI限定度适配一般用来适配图片,但真的可以适配图片吗?答案是否定的,它只在手机这种屏幕大小相对固定的设备上管用。我们在设置图片时一般使用dp作为单位,而根据DPI决定显示的dp数,比如一个小屏低分辨率的设备和一个大屏高分辨率的,他们的DPI可能相同,图片显示的实际物理尺寸就相同,很显然,他们占屏幕的比例就不一样了,如果屏幕物理尺寸差异相当大,那就面目全非了。但我们一般都使用这种方式适配图片,甚至还建立了DPI和像素之间的对应关系(其实是没有关系的),都是因为手机的实际dp相近导致的。

Android工程资源文件目录下默认会创建mdpi(160)、hdpi(240)、xhdpi(320)、xxhdpi(480)、xxxhdpi(640)这几个文件夹。一般会把不同分辨率的图片放置在这些不同文件夹里,实际上,只在一个文件夹里放置图片,在屏幕DPI发生变化时,图片也会自动按比例调整大小,但自动调整图片大小有两个问题,一是可能导致图片显示失真,二是需要消耗资源处理图片,影响程序性能。所以较好的做法是把一些非常重要,对显示效果要求很高的图片放多张,而那些很少使用、对清晰度要求不高的图片只放一张高分辨率的即可(放大图片对图片清晰地影响非常大),可减小apk体积。

关于图片适配,还有一个问题,像素图片经过缩放后,会影响清晰度,可以使用.9.png图片或者矢量图。

3.      分辨率限定符适配

分辨率适配是指定控件在基准分辨率上的显示的像素,而在其他分辨率设备上时,根据分辨率与基准分辨率的比例,将控件像素也调整成对应的比例。这种方案可参见Hongyang的技术博客,需要创建需要适配的分辨率对应的dimen文件,只需编写其中一个文件,其他的文件可用工具类自动生成,当设备的分辨率为未指定dimens文件分辨率时,会使用默认的数据。

这种方案的问题很明显,由于设备的分辨率千差万别,还有的手机有虚拟按键,导致需要创建太多的dimens文件,导致apk变大,而且在未适配分辨率的设备上,显示效果会非常糟糕。

4.      dp限定符适配

dp适配不能适配平板或特殊大小屏幕手机,针对这个问题,可以使用限定符来解决。有w-600dp,h-600dp,sw-600dp这三种dp相关限定符,sw-600dp表示较短边长度600dp以上时使用,w和h类似,但是它们与屏幕方向有关,分别表示水平边长度和垂直边长度。屏幕旋转后显示效果变化太大,一般固定屏幕方向,因此用sw-dp限定符即可。

dp适配的问题在于这种限定符是一种范围限定符,在这一范围内的不同大小的手机上显示的控件的绝对物理尺寸一样大,就导致控件相对屏幕的尺寸不一样。但这一差距一般较小,在可接受范围内。

5.             代码动态计算

优点是可精确控制显示效果,缺点是实现起来工作量大,不利于维护。

6.      百分比库

这个库是谷歌提供的,可以直接设置控件相对屏幕显示的比例,原生库只支持RelativeLayout,FrameLayout,不支持线性布局,虽然线性布局有weight属性,但无法完成一些复杂布局中的比例控制,因此有人扩展了对线性布局的支持。这个库的的目的正好与我们要实现的效果一致,看起来非常完美,但有一个小问题,美工给的素材标注都是像素,每个地方都自己计算百分比的话就有些麻烦了。

实际上Hongyang的分辨率适配方案与这个方案类似,只是在适配的时候是预处理适配的数据,但需要适配的数据太多而且不可控制。而这个库则是动态计算的,可能会稍微影响运行时的效率,但避免了预处理带来的问题。Hongyang后来提供了一个分辨率适配的动态计算方案,见http://blog.csdn.net/lmj623565791/article/details/49990941,这篇文章的标题用了“堪称适配终结者”,确实很优秀。但可能虚拟按键的处理有些问题,还有就是不是官方库,用的人不太多,可能会有未知问题。截至2017-3-6这个库在GitHub上的star有4293。

总结

手机的适配可默认为相同物理尺寸屏幕适配,直接写dp即可,不太需要适配;平板适配就同时要解决分辨率和物理尺寸两个问题,我推荐使用dp限定符适配,不同dimens文件也可以用工具类自动生成,由于是适配dp的范围,不存在适配不到的问题,只是相对比例不是绝对精确,存在很小的误差。也可以使用其他方案,推荐Hongyang的分辨率适配的动态计算方案,但要注意虚拟按键等问题。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值