为什么要做适配
由于Android系统的开放性,任何用户、开发者、运营商都可以对Android进行定制,于是导致:
1、Android系统碎片化:小米定制的MIUI、魅族定制的flyme、华为定制的EMUI等等
2、Android机型屏幕尺寸碎片化:5寸、5.5寸、6寸等等
3、Android屏幕分辨率碎片化:320x480、480x800、720x1280、1080x1920
也就是Android碎片化并不局限于手机屏幕, 为了保证用户获得一致的用户体验效果。
每一个方框代表一种 Android 设备的屏幕,颜色越深,这种尺寸的屏幕也就越多:
相关适配值
1、屏幕尺寸(英寸):是指屏幕对角线的长度,单位英寸。1英寸 = 2.54cm。
2、屏幕分辨率(px):是指屏幕横向和纵向像素点数,单位px,1px = 1物理像素,UI 设计师的设计图会以px作为统一的计量单位。
3、屏幕像素密度(dpi):是指每英寸上的像素点数、单位dpi、与像素无关的单位,像素密度是清晰度很重要的一个概念:即像素密度越高(dpi)代表显示屏能够以更高的密度显示图像
4、独立密度像素(dp):意思就是与density密度(dpi)无关,可以保证在不同屏幕像素密度的设备上显示相同的效果(px=dp*(dpi/160))。
5、屏幕尺寸、分辨率、像素密度三者关系:sqrt(1920^2 + 1080^2) / 屏幕尺寸 (三角函数--勾股定理)
Android资源下的mdpi,hdpi,xhdpi,xxhdpi,xxxhdpi如何计算和区分:目标的像素密度、资源所在的像素密度,得到一个值,然后根据这个值对图片资源宽高做缩放处理,以便达到最佳显示效果。(mipmap和drawable-xx区别)
1、mipmap目录的图标会忽略屏幕密度,回去匹配大一点的,然后系统自动对图片进行缩放,从而优化显示和节省资源下存放的资源:launcher icons、action bar and tab icons、Notification icons
2、drawable-xhdpi:如果图片放在drawable-xxxhdpi文件夹下面,而系统是xhdpi的话,它会认为这张图是为更高密度的设备所设计的,如果直接将这张图在当前设备上使用就有可能会出现像素过高的情况,于是会自动帮我们做一个缩小的操作。建议存放目录根据产品给的设计图而定,不要浪费不必要的内存
今日头条屏幕适配方案
上面已经告知今日头条屏幕适配方案的核心原理在于,根据以下公式算出 density
当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) = density
density 的意思就是 1 dp 占当前设备多少像素
今日头条适配方案默认项目中只能以高或宽中的一个作为基准,进行适配,为什么不以高为基准,宽以宽为基准,同时进行适配呢大部分市面上的 Android 设备的屏幕高宽比都不一致,特别是现在大量全面屏的问世,这个问题更加严重,不同厂商推出的全面屏手机的屏幕高宽比都可能不一致这时我们只以高或宽其中的一个作为基准进行适配,就会有效的避免布局在高宽比不一致的屏幕上出现变形的问题。
density
density在每个设备上都是固定的,DPI / 160 = density,屏幕的总 px 宽度 / density = 屏幕的总 dp 宽度
设备 1,屏幕宽度为1080px,480DPI,屏幕总dp宽度为1080 / (480 / 160) = 360dp
设备 2,屏幕宽度为1440,560DPI,屏幕总dp宽度为1440 / (560 / 160) = 411dp
可以看到屏幕的总dp宽度在不同的设备上是会变化的,但是我们在布局中填写的dp值却是固定不变的
这会导致什么呢?假设我们布局中有一个View的宽度为100dp,在设备 1 中 该View的宽度占整个屏幕宽度的27.8%(100 / 360 = 0.278),但在设备 2 中该View的宽度就只能占整个屏幕宽度的24.3%(100 / 411 = 0.243),可以看到这个View在像素越高的屏幕上,dp值虽然没变,但是与屏幕的实际比例却发生了较大的变化,所以肉眼的观看效果,会越来越小,这就导致了传统的填写dp的屏幕适配方式产生了较大的误差。
为什么传统的dp适配不行那? 原始的density = dpi / 160; (为什么是160)
屏幕的总 px 宽度 / density = 屏幕的总 dp 宽度
在这个公式中我们要保证屏幕的总 dp 宽度和设计图总宽度一致,并且在所有分辨率的屏幕上都保持不变,我们需要怎么做呢?屏幕的总 px 宽度每个设备都不一致,这个值是肯定会变化的,这时今日头条的公式就派上用场了
当前设备屏幕总宽度(单位为像素)/ 设计图总宽度(单位为 dp) = density
优点:
1、成本非常低,操作非常简单,使用该方案后在页面布局时不需要额外的代码和操作
2、侵入性非常低,该方案和项目完全解耦,在项目布局时不会依赖哪怕一行该方案的代码,而且使用的还是Android官方的API,意味着当你遇到什么问题无法解决,想切换为其他屏幕适配方案时,基本不需要更改之前的代码
3、可适配三方库的控件和系统的控件(,Dialog、Toast等所有系统控件都可以适配),由于修改的density在整个项目中是全局的,所以只要一次修改,项目中的所有地方都会受益
4、不会有任何性能的损耗
缺点:
坑一:当某个系统控件或三方库控件的设计图尺寸和和我们项目自身的设计图尺寸差距非常大时,这个问题就越严重
坑二:修改系统字体的时候字体大小未改变
坑三:系统自带的吐司,对话框都变形
坑四:webview 加载后 density 复原
smallestWidth适配方案
优点:
1、稳定,极低概率出现意外
2、不会有任何性能的损耗
3、适配范围可自由控制,不会影响其他三方库
4、在插件的配合下,学习成本低
缺点:
1、在布局中引用dimens的方式,虽然学习成本低,但是在日常维护修改时较麻烦/
2、侵入性高,如果项目想切换为其他屏幕适配方案,因为每个Layout文件中都存在有大量dimens的引用,这时修改起来工作量非常巨大,切换成本非常高昂
3、无法覆盖全部机型,想覆盖更多机型的做法就是生成更多的资源文件,但这样会增加App体积,在没有覆盖的机型上还会出现一定的误差,所以有时需要在适配效果和占用空间上做一些抉择
4、不能自动支持横竖屏切换时的适配
5、不能以高度为基准进行适配,考虑到这个方案的名字本身就叫最小宽度限定符适配方案
布局ConstraintLayout
一、较高的性能优势:布局嵌套层次越高,性能开销越大。而使用ConstraintLayout,经常就一层嵌套就搞定了,所以其性能要好很多。
二、屏幕适配:ConstraintLayout的大小、距离都可以使用比例来设置,所以其适配性更好。
三、书写简单
四、可视化编辑:ConstraintLayout也有十分方便完善的可视化编辑器,不用写xml也基本上能实现大部分功能。
match_parent:适配并不能代替match_parent,而只是为了更好的在不同屏幕上显示效果图
个人感想:
DPI的存在,不就是为了让大屏能显示更多的内容,如果一个大屏手机和小屏手机,显示的内容都相同,那用户买大屏手机又有什么意义呢?每个机型每个版本的设备都适配完美,让自己的 App体验更好,哪怕付出更大的成本,有些时候想象是美好的。
鱼和熊掌不可兼得,只是取舍问题。(也可以结合smallestWidth适配方案实现在大屏上显示应有的比例)。
xhdpi应该是首选
xhdpi分辨率以内的手机需求量最旺盛
目前市面上最普遍的高端机的分辨率还多集中在720X1080范围内(xhdpi),所以目前来看xhpdi规格的图片资源成为了首选
节省设计资源&工作量
在现在的App开发中(iOS和Android版本),有些设计师为了保持App不同版本的体验交互一致,可能会以iPhone手机为基础进行设计,包括后期的切图之类的。设计师们一般都会用iPhone6和iPhone7(6s和7s的尺寸以及分辨率都一样)来做原型设计,所有参数请看下图
iPhone主流的屏幕dpi约等于320, 刚好属于xhdpi,所以选择xhdpi作为唯一一套dpi图片资源,可以让设计师不用专门为Android端切图,直接把iPhone的那一套切好的图片资源放入drawable-xhdpi文件夹里就好,这样大大减少的设计师的工作量!