上回介绍了Android的屏幕适配,很多同学表示看了之后云里雾里的,尤其是dp这个东西,还要进行数学换算,简直是要命了。所以我决定在介绍iOS之前先花点时间再帮大家理解下Android里的dp。

1、痛点是什么?

痛点就是Android的设备碎片化非常严重,要想一一适配,设计师、开发和测试都压力山大。同一套标注,在一台手机上是一个长度,一个样子,放到另一台手机上就变形了(比如前文举的例子,如果用px,会出现不同手机大小不一样的情况)。所以大家迫切需要一套「write once,run anywhere」的通用度量单位,那就是dp了。

2、诉求是什么?

诉求就是要求在不同分辨率,不同屏幕密度上的手机上,同样dp大小的UI元素,看起来是一样大的。所谓「看起来一样大」,实际上就是要求视觉上看到的物理尺寸是差不多的,所以前文说「你可以把dp看做是一个类似厘米、英寸这样的绝对的长度单位,大约160dp等于1英寸」。

比如说,同样都是720p的屏幕,一台Nexus4,4.7寸的,另一台是6寸的华为第一代Mate,从直观上来讲,Mate屏幕会不如Nexus4显示细腻,就是所谓的颗粒感严重。从理论上讲,就是Mate的「屏幕密度」太低了。现在设计师出了一个图标,长为720px,放在两台手机上,都可以占满宽度,但是明显Mate的720px要比Nexus4的720px在尺寸上长不少。显然这是不合要求的。

3、解决方案是什么?

解决方案就是把屏幕密度纳入dp和px的换算公式里。设计师关心的,用户看到的,都是像素,是px,所以dp最后也是要换算成dp的,关键是按照1比几的比例换算。上面的例子里,Mate的屏幕密度低,显示出来就偏大,所以我们就要让这个换算比例变小。比如Nexus4上,1dp=2px,而Mate上,1dp=1.5px。这样设计师标注的同样dp的UI元素,在两个手机上就会一样大了。

这时候回过头来再看这个公式dp=(dpi/160)*px。我们就会得出两个结论。

  • 1dp可以换算成若干px,不同机型不一样。

  • 1dp到底可以换算成几个px,取决于这款手机的屏幕密度。屏幕密度越大的手机,1dp可以表示的px也就越多。

所以dp和英寸是类似的物理单位。密度越大的手机,1英寸能盛放的像素越多。密度越大的手机,1dp能表示的像素也越多,是不是这个道理?

所以dp才被叫做密度无关像素(density-independent pixel)。因为无论手机的屏幕密度是多少,1dp总是对应着差不多的物理尺寸。

但是,说了这么多其实都是废话,你只需要记住一点就够了:

  • mdpi区间的手机,dp=px。

  • hdpi区间的手机,1dp=1.5px。

  • xhdpi区间的手机,1dp=2px。

  • xxhdpi区间的手机,1dp=3px。

然后我们再来看iOS。其实Android要面对的问题,iOS同样存在。iPhone虽然机型不多,但是经过几次更新换代,屏幕也从最早的3GS(320*480)进化到了现在的iPhone6 plus(1920*1080)。屏幕密度越来越大,如果直接用px的话,还是会出现同样px的UI元素,在不同机型上的大小不一样的问题。于是iOS很机智的选择了点(point)这个和dp几乎一模一样的虚拟单位。

  • 在3GS上,1point=1px。

  • 在iPhone4上,1point=2px。

  • 在iPhone5上,1point=2px。

  • 在iPhone6上,1point=2px。

  • 在iPhone6 plus上,1point=3px。

为什么1point对应的px数逐渐增大呢?参考Android,根本原因还是屏幕密度越来越大了。比如3GS,3.5英寸的320*480,到了iPhone4,就是3.5英寸的640*960。屏幕尺寸没变,分辨率提升了一倍,密度自然就提升了一倍。

相应的,对于图片,iOS的图片资源可以在名字后面加上@2x表示它是2倍的资源,@3x表示他是3倍的资源,例如icon@2x.png,avatar@3x.png。2倍的资源放在2倍的机型上,完美适配,不需要缩放。但是放在1倍的机型上,就要被系统自动压缩,放在3被的机型上,就要被自动拉伸。对比一下,Android则是把不同分辨率的图片放在不同的文件夹下来区分。二者如此惊人一致。

仔细观察上面的iPhone设备表格,有两个机子比较奇葩。

一个是iPhone5。还记得当年人们说的长长长长长下巴吗?iPhone5和iPhone4都是2倍的屏幕,但是iPhone5的屏幕高度却比iPhone4多了176px。如果程序没有适配iPhone5,跑在iPhone5上就会出现黑边。那么如何告诉系统你的程序已经适配了iPhone5呢?很简单,在程序里添加一张APP起始图片,命名为Default-568h@2x.png就行了。当然,你的UI布局也要相应改变,还好系统从iOS6开始提供了一种AutoLayout,可以用来构建兼容不同屏幕尺寸的界面(改天再细讲)。

另一个是iPhone6 plus。我们来算个账先,iPhone5的屏幕密度是326,倍率是2,那么屏幕密度401的iPhone6 plus,怎么算也不应该是3倍,而是2.46倍啊。但是,2.46这个数字太抽象,苹果为了方便大家计算,还是强行用上了3倍的scale。苹果规定,在iPhone6 plus上,开发者用3倍的资源,也就是按照1242*2208的分辨率出图,然后系统会强制缩放成1920*1080,其实效果也差不了多少。

不得了了,连iOS的机型都这么多了,设计师怎么办啊?还是那句话,以不变应万变。上一回讲Android的时候,提到说可以选择一套基准的分辨率进行标注和出图,然后让系统去自动缩放,其实拿到iOS这里也是可行的。比如你选iPhone6的750*1334为基准,然后向上等比缩放1.5倍到接近6p的1225*2001出3倍资源,向下等比缩放来适配3GS-5s的机型。

哦,对了,还要让开发尽量用AutoLayout来排版布局UI元素。

如果各位感兴趣的话,下回讲讲web前端是如何适配屏幕的。

本文来自给产品经理讲技术(微信公众号:pm_teacher)授权发表,转载请联系原作者,违者必究。