一.为什么要进行屏幕适配
先看几个图片
Android设备
从上面图片可以看出安卓设备屏幕的种类太多,为了让我们开发的APP在每一个设备上都能达到期望的显示效果,所以我们在开发过程中需要做适配工作。
二.基本概念
- px:像素点。例如通常所说的手机分辨率1920*1080,指的就是高度上有1920个像素点,宽度上有1080个像素点。
- dpi:每英寸的像素个数。dpi是物理尺寸每英寸内的像素点个数。每台手机都有他固定的dpi。
屏幕尺寸,分辨率、像素密度三者关系。
举个例子,华为mate 20 分辨率2244*1080 屏幕尺寸6.5 英寸,用上面的公示,mate20屏幕密度==383
安卓官方对密度类型的分类定义如下图,383的屏幕密度属于xhdpi,目前主流手机或者pad的屏幕都是 超高密度(xhdpi)和 超超高密度(xxhdpi)
密度类型 | 屏幕像素密度 (一英寸有多少个像素点) | 官方规定的dpi范围 | 代表分辨率和尺寸 | 真实代表手机型号 |
低密度( ldpi ) | 120dpi | 120~160 | 240x320 3.3inch | 太稀有,找不到 |
中密度( mdpi ) | 160dpi | 160~240 | 320x480 3.5inch | HTC G1 320*480 3.2 inch |
高密度( hdpi ) | 240dpi | 240~320 | 480x800 3.8inch | 小米1S 480*845 4inch
|
超高密度( xhdpi ) | 320dpi | 320~480 | 720x1280 4.5inch | 红米note7 2340*1080 6.3inch 小米9 2340*1080 6.3inch |
超超高密度(xxhdpi) | 480dpi | 480~640 | 1080x1920 4.5inch | 华为mate20pro 3120*1440 6.3inch |
- dp:安卓系统内的计量单位。dp 就是让开发者在代码中设置的尺寸单位,相同的dp值可以再不同dpi屏幕上显示不同的像素点数量,达到相同的显示效果。
安卓官方标准是160dpi屏幕上的1px 作为标准定为1dp. 那么在160dpi的设备屏幕上1dp就是1px。在240dpi的设备屏幕上1dp就是1.5px 。
这就是安卓系统内用来适配不同dpi
注意:为什么是160dpi呢,因为谷歌就是这么规定的,第一台安卓设备HTC G1 是160dpi的屏幕。
在安卓系统中dp值是如何换算成px显示的呢? 看下面的表格。
举个例子说明安卓为什么使用dp
例:
两台设备
A.480px*320px 3.5英寸 160dpi
B.800px*480px 3.8英寸 240dpi
UI设计师按照A手机为标准给出的设计图,设计图效果是在屏幕左上角布局一个长方形控件,控件长宽240px*160px
如果我们按照设计的标注240px*160px定义一个控件放在左上角。
使用px作为单位和使用dp作为单位在两手机上显示的效果如图所示
可以看出一个240px * 160px的元素当使用px为单位:在480*320的屏幕上显示效果,占用屏幕宽度的1/2。此时将该尺寸放在800*480屏幕上显示效果变为屏幕宽度的1/3了。
总结:dp解决的到底是什么问题?
dp使得在任何规格的屏幕上160dp都等于或者接近于物理尺寸1英寸
为什么是接近于而不是完全等于?如果所有的屏幕厂商都按照谷歌标准的160,240,320...来生产那屏幕,那么所有设备上160dp可以完全等于1英寸。实际上,市面上屏幕的规格很多,以华为mate20为例,实际的dpi=388也就是说实际的规格是每一英寸像素是388px。按照谷歌的标准属于xhdpi 320dpi的屏幕密度,160dp在mate20手机上被系统转化成320px显示,物理尺寸只有320/388 = 0.8英寸。
dp只是解决了屏幕密度适配的一部分问题。
- sp:sp和dp类似,sp会根据系统设置里的字体大小来变换,所以在字体设置上最好用sp。
三.UI适配的本质和解决方案
- 我们先举两个比较极端的适配问题的案例便于理解适配问题。
(1)
例1 :
两台设备屏幕规则相同都是160dpi的密度,但是尺寸相差大
A.480px*320px 3.5英寸 160dpi
B.800px*480px 5.8英寸 160dpi
在屏幕画一条直线占屏幕一半。
如果设计师给的设计图按照A手机的标准出的,标注的直线长度是160px
错误的做法:按照A手机的屏幕尺寸定义直线的宽度为160dp
结果:在A手机中正常显示,B手机中线的长度只有1/3
在相同屏幕密度,不同尺寸的屏幕上,要显示相同的效果。通常我们把这种问题的称为屏幕尺寸适配问题。
(2)
例:
另一种适配问题如下图,同样的图片在手机A上显示正常,在手机B上就模糊了.
图片的分辨率是480*800
手机A的分辨率也是480*800
手机B的分辨率是1080*1920
所以图片在手机A上正常显示,在手机B上则被放大到1080*1920就模糊了,通常我们把这种问题定义为屏幕密度适配问题。
安卓屏幕适配问题的本质大概就是这两类
1.屏幕尺寸适配
使得“布局”、“布局组件”、“图片资源”、“用户界面流程”匹配不同的屏幕尺寸
2.屏幕密度适配
使得“图片资源”匹配不同的屏幕密度
- 屏幕尺寸的适配
(1)布局适配
本质:使布局自适应屏幕尺寸
解决方案:1.使用相对布局(RelativeLayout),不用绝对布局(AbsoluteLayout)
2.根据屏幕的配置来加载相应的UI布局。
(2)布局组件适配
本质:使布局组件自适应屏幕尺寸
解决方案:1.对于组件的宽高,不要写死,尽量使用wrap_content,match_parent,weight来组合使用达到效果。
(3)图片资源适配
本质:使得图片资源自适应屏幕尺寸,同时还不能变形,失真。
解决方案:通过上面的第一点,第二点来保证我们APP内加载图片的view的尺寸能自适应屏幕,从而使得图片也能自适应屏幕。但是会出现两种状况
1.图片的宽高比例被改变从而被拉伸变现
2.或者放大失真的情况。
对于被拉伸变现的情况我们可以通过制作.9图片来达到效果,入下图所示,同一个.9图片被拉伸用来适配不同屏幕显示相同的效果。
对于放大失真的情况,我们在下面的屏幕密度适配部分会解决。
(4)用户界面流程适配
本质:对于不同尺寸的屏幕,我们APP的操作流程会做出相应改变来适应用户操作,例如同一个APP在pad上两个页面分左右屏显示,在手机上需要跳转显示。
解决方案: 代码中处理,涉及安卓中代码比较多,不详细讲了
例: 我们的App要满足下面两种情况,在手机上,A和B之前是跳转,在平板上,A和B是同一个页面,这就是用户界面流程的适配
总结:经过以上屏幕尺寸的适配基本能解决大小适配的问题,使得APP在不同设备上都能正常显示正常的尺寸。
- 屏幕密度的适配
屏幕密度的适配,本质上是使APP在不同密度(dpi)的屏幕上都能显示正确的像素效果(与屏幕大小无关)
(1)布局控件匹配
本质:使得布局组件在不同屏幕密度上显示相同的像素效果
解决方案1:使用dp作为计量单位 。
安卓系统PX和DP换算规则
dp的原理和解决的问题在上面介绍dp的时候已经说过。
那么在密度适配上使用dp就是万能了吗?看下面一种情况
例如
两款手机
nexus5 标准的1920*1080 480dpi 屏幕的手机 根据1dp=3px换算总宽度360dp
nexus one 标准的800*480 240dpi 屏幕的手机 根据1dp=1.5px换算总宽度320dp
在nexus5中,在水平方向设置两个按钮按钮宽度固定100dp,左边按钮距离左边80dp,右边按钮距离右边80dp,这样两个按钮正好居中,中间间距为0,如图所示
代码:
在nexus 5中的显示效果
在nexus one中的显示效果缺变成这样,俩按钮重叠了
结论:dp解决的问题跟手机屏幕大小无关,dp解决的是让160dp在任何规格的屏幕上都能显示1英寸左右的物理尺寸,dp解决了同一数值在不同分辨率中展示相同尺寸大小的问题(即屏幕像素密度匹配问题),但却没有解决设备尺寸大小匹配的问题。(即屏幕尺寸匹配问题)。
当然,我们上面说的屏幕尺寸匹配问题,使用match_parent、wrap_content和weight,尽可能少用dp来指定控件的具体长宽,也能解决这两个按钮的重叠问题。但是如何通过屏幕密度适配的方式来解决屏幕尺寸大小不一导致的问题呢?接着我们分析下面的解决方案2.
解决方案2:百分比适配法——不用dp而用px来作为单位,用百分比的方式定义控件,按照UI设计师给的标注设置就行,不需要任何转换。
这种方案跟web开发中的百分比设置类似。
步骤如下:
1.以某一分辨率为基准,生成所有分辨率对应像素数列表
2.将生成像素数列表存放在res目录下对应的values文件下
3.根据UI设计师给出设计图上的尺寸,找到对应像素数的单位,然后设置给控件即可
详细步骤内容比较多,不介绍了,参考博客
总结:百分比适配就是把市面上所有的手机的分辨率配置到项目中,以其中一种分辨率作为标准其他的按照比例配置在项目中,设计师也按照这个标准分辨率出效果图,这样开发只需要设置PX标注,不用管dp跟px的复杂关系,手机会根据实际屏幕分辨率去对应目录文件内找到我们提前配置好的px 。理论上只要配置里涵盖的屏幕分辨率齐全,就能100%适配。
优点:只要适配的手机屏幕分辨率已经配置,那么100%完美适配
缺点:不是谷歌官方推荐,需要不断更新配置文件满足市场上的新手机,配置文件会增加安装包的大小,对于屏幕的宽高比无法适配(例如,一个正方形控件,设计师的效果图是按照1280*720设计的,用百分比适配法设置的宽和高,那么在1280*720的手机上显示是正方形,但是在480*320的手机上却不是正方形),还存在一些不确定的坑(比如某国产手机被深度定制过,可能)。
(2)图片资源匹配
本质:使得图片资源在不同屏幕密度上显示相同的像素效果
解决方案1:提供备用位图。
需要根据以下表格中类型,每个类型设计一套资源,分别存在APP的相应目录中,app运行时安卓系统会根据实际屏幕选择最合适的。
注意:如果UI设计师为每个类型的像素密度设计一套图片,不但增加设计师工作量,也会增加APP包的大小。
解决方案2:更好的解决方案
原理:安卓手机在加载APP的资源图片的时候,会先判断当前手机的分辨率和密度,在到相应的文件夹内加载对应图片,如果没有就会将找到的图片放大或者缩小,图片缩小并不会影响显示效果,图片放大则会失真,所以我们只要提供最高分辨率的图片存放在对应目录内就行。
做法:让UI设计师选较高分辨率为标准制作图片,选720*1280或者1080*1920,至于具体选哪个,根据实际情况选择,标准越高切图也会越大,会导致安装包越大。
iPhone主流的屏幕dpi约等于320, 刚好属于xhdpi,所以以iPhone主流屏幕为标准的UI设计也符合安卓主流屏幕的标准,可以让设计师不用专门为Android端做设计和切图,直接把iPhone的那一套效果图和切图拿给安卓用,这样大大减少的设计师的工作量!
四.总结:
根据统计 ,超过一半的安卓设备屏幕是320dpi的,超过一半的设备尺寸是5英寸和5.5英寸,超过一半的设备分辨率是1920x1080和1280x720。
经过上面的分析,大概理解了安卓屏幕的适配原理和各种适配方式。但是UI设计师和安卓开发到底需要怎么做?
对于UI设计师
需要按照1920x1080或者1280x720的分辨率来设计UI和切图。
因为5.5寸或者4.7寸的iPhone也符合安卓主流设备所以也可以用iPhone的设计图和切图给安卓用。
建议按照1920x1080,或者iPhone8+(2208x1240)的分辨率设计。
对于安卓开发人员
1.多用相对布局和wrap_content等自适应的属性,避免使用绝对布局或者直接设置控件宽高值。
2.不管是1920分辨率的切图,还是1280分辨率的切图都放在xhdpi文件内,因为安卓主流设备是320dpi范围内的默认会在xhdpi内找图片资源。
3.在设置标注时,如果用dp作为计量单位时,根据设计师的UI图标注的PX,需要自行转换dp,如果是1920x1080的图或者iPhone8+的设计需要px值需要除3得到dp值,如果是1280x720的图或者IPhone8的设计图需要px值需要除2得到dp值。
4.对于百分比适配法,建议引入项目,可以小心使用,长期使用验证后没问题可以代替dp。
5.对于字体的设置要用sp作为单位