Android适配是一个大坑,你可能早有耳闻。但是别人告诉你坑,然后你也说坑,肯定是无法令人信服的。我们做学问,不能光知其然不知所以然,适配问题到底有多坑,为什么坑,以及如何从坑里爬出来,就是我们今天要探讨的话题了。
这还得从Android的开放性说起。不同于iOS,Android的设备厂商可以生产任意屏幕大小的手机、平板和TV,谷歌对此并没有做任何限制。直接后果就是设备越来越多,大大小小的屏幕尺寸也是层出不穷。另一方面,程序员都有一个梦想,就是一套代码走天下,谁都不想把美好青春浪费在应付各种奇葩的屏幕适配上去。所以说程序员一谈适配色变,尤其是Android的适配,简直比产品经理改需求还要痛苦。这里有两张图,你可以看下当前形势多么严峻。
Android设备碎片化情况
Android设备屏幕尺寸情况
也就是说,我们开发一款Android App,就要对成千上万种屏幕尺寸做适配吗?非也。魔高一尺道高一丈,为了能又精准又省事儿的完成适配,这里有不少方法可以用,我们先从几个基本的概念说起。
1、像素(px)和分辨率。
我们的显示屏是由一个一个肉眼看不见但是放大镜可以看见的小点点组成的,这些点点就是像素,是物理世界中存在的东西。分辨率是你的显示屏一共有多少像素。我们平时说的分辨率是1920*1080,就是所谓的1080p,意思是显示器上水平方向有1920个像素,垂直方向有1080个像素,乘起来大概是200W个像素。
2、屏幕密度(dpi)。
屏幕密度是对角线上每英寸的屏幕包含多少个像素。比如你手里的iPhone 6 plus,对角线有5.5英寸长,分辨率是1920*1080,那么根据勾股定理(还记得吗,小学语文老师讲过的哦),对角线上有2203个像素,屏幕密度就是2203/5.5=400,单位是dpi或者ppi,二者是一个意思。
在此基础上,Google顺便把手机按照屏幕的密度分了几个档次:
现在主流的手机,都可以找到自己所在的屏幕密度档次。比如一般来说720p的手机是xhdpi,1080p的是xxhdpi。还有一种情况,比如同样都是4英寸的480*800和4英寸的960*540,尽管实际算出来的dpi不一样,但是都要归到hdpi这一档,dpi都变成了240,这是Android系统做的一种近似处理,目的是为了简化计算。也就是说,虽然实际上手机的密度有很多种,但是大家会找到自己的近似区间,然后用区间的代表值去做运算。
3、密度无关像素(dp)
dp是一个虚拟的概念,是在程序运行的时候算出来的。怎么理解呢?Android设备那么多,分辨率也那么多,直接学iOS用px做单位肯定不行的。为此Google搞了一个叫dp的东西,换算公式是dp=(dpi/160)*px。也就是说,在密度为160dpi的屏幕上,1px就是1dp。依次类推,在320dpi的屏幕上,1dp就是2px。屏幕密度越大,1个dp对应的px也就越多。
根据前面讲的屏幕密度区间,你可以记住这样一个简单的计算方法:
mdpi区间的手机,dp=px。
hdpi区间的手机,dp算px要乘以1.5。
xhdpi区间的手机,dp算px要乘以2。
xxhdpi区间的手机,dp算px要乘以3。
xxxhdpi区间的手机,dp算px要乘以4。
用dp有什么好处呢?假设我们现在有两台手机,一台是1280*720,320dpi,一台是1920*1080,480dpi。设计师同学给了一个标注是360px,放在第一台手机上正好是屏幕宽度的一半,但是放在第二台的手机上,则只有宽度的1/3了。这显然是不行的。现在设计师改成了180dp,那么根据公式,在320dpi的手机上,180dp=360px是屏幕宽度720px的一半。在480dpi的手机上,180dp=540px也是屏幕宽度1080px的一半。所以你看到了,dp是用来屏蔽手机的像素密度的差异的,相同dp的标注,在不同分辨率的屏幕上,实际大小都是一致的(从这个角度讲,你可以把dp看做是一个类似厘米、英寸这样的绝对的长度单位,大约160dp等于1英寸)。
相应的,在开发的时候,Google提供了一些资源目录,你可以把对应大小的图片放进去。
举个例子,你想展示一张100dp*100dp的图片,那么在mdpi目录下,你需要放100px*100px的原图。在xxxhdpi下,这张图片就得是300px*300px。你的APP在运行的时候,如果需要加载这张图片,系统就会根据当前手机的密度,去相应的资源目录下去找。你可能会问,找不到怎么办呢?比如当前是mdpi的手机,系统发现mdpi下没有这张图,就会去比mdpi更大的目录找,然后进行缩放。实在找不到就去比mdpi更小的目录找,找到之后再拉伸。
那么,设计师在出图的时候,有两种方法可以选。一是按照官方的推荐方法,在上面所有目录下各放置一份同样的图片,根据dp和px的换算关系切成不同的大小,让系统自动去寻找最合适的图片。这种方法成倍的增加设计师的工作量不说,还会增加安装包的体积,用户下载的时候要多耗费流量,可能过不了隔壁产品同学这一关。第二种方法是选一个基准的屏幕密度,比如xhdpi,720p。所有的资源都放在这里,让系统自动去缩放。这种方法呢,对于小屏幕的手机来说,因为要在运行的时候把一张大图缩放成小图,不如直接用小图节省内存。对大屏幕的手机呢,比如你720p的图拿到1080p的手机去显示,肯定会因为缩放而失真。
综合起来的话,我更倾向于第二种方法。具体选择哪种屏幕密度做标准,你可以参考下Google官方的统计。
还有一些准则,有必要交代一下。
尽量是用dp,这是最基本的。
如果你使用xhdpi(一般是720p)为基准进行标注,注意它的屏幕宽度是360dp(720/2),而对于hdpi及以下的手机,比如480*800,屏幕宽度是480/1.5=320dp。此时如果你标注的长度超出320dp的话,最好换一种方式。