Android屏幕适配前先了解这些

前言:以前很火的屏幕适配方案不知道你们都去尝试过写进项目中没,应该有一部分人在隔岸观火,大概的缘由就是目前并无遇到能把项目重构的适配问题,另外一方面就是有的适配方案尚未很成熟的应用,都不想拿本身的项目去测试。就拿那些github开源库上面的适配方案来讲,没有几我的去上面提issues。就在最近我去试了一下今日头条的适配方案,而后。。。哎~~接着往下看吧java

一 ppi和dpi这两个单位是什么?有什么关系?

ppi(Pixels per inch) 指每英寸上的物理像素数数目,即 "像素密度“。通常再购买手机的时候都会在参数中看到该设备的ppi数值,ppi数值越大屏幕显像效果越好。不过ppi是物理上的概念,是客观存在的不会改变的值,跟开发中常见的dpi是彻底不一样的。android

dpi(Dots Per Inch)指每英寸有多少个点,最初是用在印刷行业,用来描述每英寸有多少小黑点。dpi被用于Android开发中用来描述屏幕像素密度的单位,是手机出厂就写在系统配置中的一个固定数值,通常是固定不变的,除非你root以后去系统文件中修改这个值,不过手机root有太多的风险,不推荐去root,开发中能够用DisplayMetrics类去获取dpi数值。git

ppi和dpi是没有任何关系的。有些文档中ppi 等于 dpi的言论都是瞎扯的,它们之间也没有什么换算关系,还有的文章说 dpi的取值取决于ppi处于哪一个dpi的范围,而后取这个范围最大的值,这一点是没有任何的依据,至于dpi的赋值咱们也没法得知手机厂商是根据什么去肯定的。github

ppi的数值咱们能够经过如下公式算出,通常的话手机参数里面都能看到ppi的数值,该公式并不适用计算dpi。json

dpi不能用上面的公式求出,dpi能够经过DisplayMetrics类的densityDpi属性获取当前手机的dpi数值,该类也能够获取到跟屏幕密度有关的其它属性。通常获取DisplayMetrics类有如下方法:app

方式1:
//content:Activity,Content,Application. 
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
方式2:
//getSystemService能够经过 Activity,Content,Application等获取.
 DisplayMetrics displayMetrics = new DisplayMetrics();
 WindowManager windowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
 windowManager.getDefaultDisplay().getMetrics(displayMetrics);
复制代码

二 为何dp知足不了如今的屏幕适配(设计图按1080x1920设计)?

为何强调设计图呢, 由于设计图是UI设计师根据APP的类型以及使用场景精心设计的,同时设计稿直接决定app界面预期的显示效果,决定了每一个控件预期的大小,而屏幕适配也是要解决在Android尺寸限制的范围内,按照一套设计图写出的布局要在大部分机型上面显示效果都跟设计图同样。通常的设计师会给一套尺寸,好比1080 X 1920 即 360dp X 640dp 比例 9:16的,或者IOS和Android使用一套设计图(通常都会让Android用IOS的设计稿)。在没有严格要求的话咱们只是使用了dp来写布局, 反正如今一直都是😭,渐渐的发现dp已经逃不过设计师的法眼了(好多机型显示的效果都跟设计图有较多的差别)。ide

接着看,国内Android手机的ppi数值是厂商定制的,跟手机的硬件相关,ppi数值越大显像效果越好,但ppi只是描述了手机硬件方面的像素密度,并不用于开发中。每种通用的尺寸和密度都涵盖一个实际屏幕尺寸和密度范围。例如, 两部正常屏幕尺寸的设备在手动测量时,实际屏幕尺寸和 高宽比可能略有不一样。相似地,对于两台hdpi 屏幕密度的设备,其实际像素密度可能略有不一样。 Android 将这些差别抽象归纳到应用,使您能够提供为通用尺寸和密度设计的 UI,让系统按须要处理任何最终调整。(有可能Android手机系统出厂设置的dpi数值也会参考该取值范围的)。布局

Android DPI区域划分

ldpi(低)~120dpi
mdpi(中)~160dpi
hdpi(高)~240dpi
xhdpi(超高)~320dpi
xxhdpi(超超高)~480dpi
xxxhdpi(超超超高)~640dpi

小屏幕至少为 426dp x 320dp
正常屏幕至少为 470dp x 320dp
大屏幕至少为 640dp x 480dp
超大屏幕至少为 960dp x 720dp
复制代码

为了简化屏幕适配,通常机型的dpi的取值会参考上面的范围,可是总会有一些特殊的机型就是不采纳官方的建议。如小米 MIX 2 分辨率 2160x1080 屏幕尺寸 为6, ppi为403 获取到的dpi为440,该分辨率下的手机dpi 大体为480。为何要强调dpi的数值呢?我想你们都知道咱们再布局的尺寸方面都会选择dp,由于dp是会随着分辨率的不一样而变化的,通常的关系以下:学习

dpi 120 : 1dp = 0.75px;
dpi 160 : 1dp = 1px;
dpi 240 : 1dp = 1.5px;
dpi 320 : 1dp = 2px;
dpi 480 : 1dp = 3px;
dpi 640 : 1dp = 4px;

计算公式:
px = density * dp;
dp = px / density;
density = dpi / 160;
复制代码

根据上面的公式能够看到dpi影响了dp转px的数值,因此能够说dp适配也就是dpi的适配,对于360dp X 640dp的设计稿来讲,对应的分辨率为1080 X 1920和1440 X 2560,使用的数值为 1dp = 3px。正常的机型咱们使用dp的话基本能够完成适配,可是当碰到分辨率同样dpi不一样的手机,好比dpi = 440 1dp = 2.75px 或者 dpi = 420 1dp = 2.625px 的机型的时候,那就懵逼了,如一个Button的宽度为100dp,再dpi = 480的机型中显示的宽度效果为300px,再dpi = 440显示的效果宽度为275px,这样咱们的布局就会跟预期的不太同样,这是dp没法适配的。测试

另外如今主流的是大屏手机,长度方向的像素点通常大于1920px,大体在2040px~2880px之间,可是宽度基本保持再1080px,配置好的手机是1440px,市场90%以上主流手机宽度都是1080px的。如:

华为:
nova 2s ,Mate 10 Pro 等等分辨率是2160X1080  dpi = 480  ;
nova 3 2340 x1080  dpi = 480;
小米:
MIX 2040x1080  dpi = 480,  MIX2 2160x1080  dpi = 440 ,
Max 2160X1080  dpi = 480等等;
oppo:
R11s 2160x1080  dpi = 480, R15 2280x1080  dpi = 480,
等等...
复制代码

手机dpi的大小决定了当前dp转px的倍数关系,目前大部分机型的dpi都是480,也就是说设计图上一个组件的margintop 为100dp = 300px,那么当运行在分辨率为1080X2280的机型中该组件相对于设计图的位置就会偏上,在分辨率为1080x1920的机型中正常,这就会致使一个问题,在大屏手机中正好显示完整的布局会再小屏幕中就会出现控件被遮挡或者控件的高度比不一致,最明显的就是开屏页的logo位置。这也是dp没法解决的适配问题。

我的而言,适配宽度用dp基本可以适配,毕竟那些特殊dpi的机型仍是少数,写布局注意点的话就不会出现太明显的适配问题。适配高度就须要使用其余的更有效的适配方式了。

三 宽高限定符,AndroidAutoLayout,smallestWidth,今日头条适配方案怎么取舍?

宽高限定符适配和smallestWidth适配方案大体思想都是同样,smallestWidth比宽高限定符更加的智能可靠。可是这两种方案须要增长好多资源文件,想要适配什么屏幕就要去配置该类型的资源文件,全局适配。这两种适配方案再宽高适配上仍是颇有效果的。鸿神的AndroidAutoLayout已经中止维护了,我想你们都不会优先考虑这个方案了,这里也不去讨论。今日头条适配方案我想你们都或多或少的了解过,该方案仍是比较精简灵活的,能够本身选择以宽度适配仍是高度适配,下面是在高度纬度上面的测试数据:

设计图: 
360dp X 640dp 分辨率为 1080 X 1920 这里的屏幕高度包括状态栏。
控件高度为103dp  高度/屏幕高度 = 0.1609375.
      
    
    
模拟器 1: 
分辨率为 1080 x 2280 .实际是 1080 X 2136 .状态栏高度Wie:72px.   
控件高度为103dp  高度/屏幕高度 = 0.1497093. 适配后:0.1609649.

    
    
模拟器 2: 
分辨率为 1080 x 1920 .实际是 1080 X 1776 .状态栏高度Wie:72px.   
控件高度为103dp  高度/屏幕高度 = 0.18133803.适配后:0.16035.


    
模拟器3:
分辨率为 480 * 800.状态栏高度Wie:36px.   尺寸小于设计图的.
控件高度为103dp  高度/屏幕高度 = 0.19375. 适配后:0.16125.



小米4: 
分辨率为 1080 x 1920  .状态栏高度Wie:60px.   
控件高度为103dp  高度/屏幕高度 = 0.16612904. 适配后:0.1609375.



小米MIX2: 
分辨率为 1080 x 2160  .状态栏高度Wie:66px. 底部虚拟导航键高度为:130px   
控件高度为103dp  高度/屏幕高度 = 0.13940887. 适配后:0.16108374.



OPPO R15:  
分辨率  1080 x 2280.  尺寸是 6.28 .  状态栏高度为:84px.
控件高度为103dp  高度/屏幕高度 = 0.13552631.  适配后:0.1609649.



华为p20: 
分辨率为 1080 x 2240  .状态栏高度Wie:85px.   
控件高度为103dp  高度/屏幕高度 = 0.13770053.适配后:0.16087344.



oppo R9s: 
分辨率为 1080 x 1920 .状态栏高度Wie:54px.   
控件高度为103dp  高度/屏幕高度 = 0.1609375. 适配后:0.1609375.

复制代码

用今日头条的适配方案后再大屏手机中的高度比基本等于设计图中的高度比,这样在屏幕高度相差很大的真机环境中显示效果会好不少。今日头条适配方案更加的灵活,咱们再适配的时候虽然是全局的修改,可是咱们能够指定特定的界面上不适配(也就是把设置恢复为默认的设置),这样即便是第三方的界面只要有代码就能够选择适配适配。另外还能够的自由的配置是以宽度为基准仍是以高度为基准点去适配,可是二者不能兼得。

四 今日头条适配方案到底可行吗?

那么问题来了,再平常开发中只是适配宽度的话,碰见的需求很少,适配高度确实是碰见很多,而后我再适配高度的时候发现了问题。当咱们用今日头条适配方案在高度上去适配大屏手机的话(好比分辨率为1080X2160)那样计算出来的dpi的数值确定会比原数值高好多。好比小米 MIX2 分辨率为 1080 X 2160 高度适配以后再高度纬度的dpi数值为523 那么就是100dp = 317px,正常状况的dpi为440 100dp = 275px。高度适配以后对宽度方向影响很大的。对下表的数据分析能看出,目前流行机型的宽度定大部分都在1080,高度大于1920的机型居多,再大屏手机里面咱们要首选适配高度的问题,先来看下一个简单的适配问题。

需求: 开屏页logo展现位置。

设计稿: 1080px X 1920px 360dp X 640dp。

logo: 大小100dp X 100dp 水平居中,marginTop100dp。topMargin / 屏幕高度:0.15635。

测试机型: 小米四(1080X1920) vivo x21(1080X2280)。

真机数据未适配前:

未适配前:
小米4:  
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getWidth300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getHeight300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: topMargin / 屏幕高度0.15625

VIVO X21:
10-12 10:31:15.246 23724-23724/cn.screen.adaptation E/WANG: getWidth300
10-12 10:31:15.246 23724-23724/cn.screen.adaptation E/WANG: getHeight300
10-12 10:31:15.246 23724-23724/cn.screen.adaptation E/WANG: topMargin / 屏幕高度0.13157895

咱们能够看到小米4手机的topMargin / 屏幕高度跟设计图的一致。VIVO X21就相差很大了。这样显示出来的logo的位置就会跟设计图设计的有很大的差距,这种差距是随着手机竖直分辨率的增大而增大。
复制代码

真机适配后:

高度适配后:
小米4:  
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getWidth300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: getHeight300
10-12 10:28:25.146 12746-12746/cn.screen.adaptation E/WANG: topMargin / 屏幕高度0.15625

VIVO X21:
10-12 10:30:33.760 23502-23502/? E/WANG: getWidth356
10-12 10:30:33.760 23502-23502/? E/WANG: getHeight356
10-12 10:30:33.760 23502-23502/? E/WANG: topMargin / 屏幕高度0.15614036
    
咱们能够明显的看到logo的topMargin / 屏幕高度基本跟设计搞的一致,这样就达到了logo在大多数机型上面显示的效果跟设计稿的同样。可是能够发现logo的宽高都增长了56px,这也是由于适配高度的时候更改了dpi的数值,dpi的数值偏大就会形成全局的dp转px的倍率变大,这样咱们的logo的大小和该界面的其它的控件的大小都会有影响。    
复制代码

总结:

屏幕适配任重而道远,咱们要针对设计稿,针对界面,针对控件去选择咱们的适配方式,技术好并不表明好用,有的时候会反其道而行之。本人仍是很喜欢今日头条适配方案的,用注解作起来逼格瞬间提高,想再那个界面适配就在那个界面适配,想取消适配就取消适配,也就一个注解的事。另外还有一点就是,适配方案推出那么多时间也不短了,有几个开发者实战了呢?所谓实践出真理今日头条适配方案坑不少,咱们一块儿慢慢踩~~欢迎你们提出文章里面的错误,你们共同窗习!

参考 developer.android.google.cn/guide/pract…

欢迎关注:
个人掘金
个人简书
个人CSDN
个人Github

注解版今日头条适配方案 (供参考学习)

五 主流机型

注: 如下机型的dpi数值只有一部分获得真机验证,其他存在些许偏差望更正,体如今(宽/density)这个数值上。

华为-荣耀系列:

机型 分辨率 ppi 尺寸 宽/density 高/density
华为畅享8 1440x720 269 5.99 360dp 720dp
华为nova 2 1920x1080 440 5 360dp 640dp
华为P9 1920x1080 424 5.2 360dp 640dp
华为Mate 9 1920x1080 373 5.9 360dp 640dp
华为P10 1920x1080 432 5.1 360dp 640dp
华为Mate 10 Pro 2160x1080 402 6 360dp 720dp
华为nova 2s 2160x1080 402 6 360dp 720dp
华为畅享8 Plus 2160x1080 407 5.93 360dp 720dp
华为Mate 10 Pro 2160x1080 402 6 360dp 720dp
华为nova 2s 2160x1080 402 6 360dp 720dp
华为P20 Pro 2240x1080 408 6.1 360dp 746.7dp
华为P20 2244x1080 428 5.8 360dp 748dp
华为nova 3e 2280x1080 432 5.84 360dp 760dp
华为nova 3i 2340x1080 409 6.3 360dp 780dp
华为nova 3 2340x1080 409 6.3 360dp 780dp
华为Mate 10 2560x1440 498 5.9 360dp 640dp
华为Mate 20 2560x1440 482 6.1 360dp 640dp
华为Mate RS保时捷版 2880x1440 537 6 360dp 720dp

小米:

机型 分辨率 ppi 尺寸 宽/density 高/density
小米红米6 1440x720 295 5.45 360dp 720dp
小米Max 2 1920x1080 342 6.44 360dp 640dp
小米5X 1920x1080 401 5.5 360dp 640dp
小米6 1920x1080 428 5.15 360dp 640dp
小米Max 2 1920x1080 342 6.44 360dp 640dp
小米MIX 2040x1080 361 6.4 360dp 680dp
小米6X 2160x1080 403 6.0 360dp 720dp
小米MIX 2s 2160x1080 403 6.0 360dp 720dp
小米红米Note 5 2160x1080 403 6.0 360dp 720dp
小米Max 3 2160x1080 350 6.9 360dp 720dp
小米MIX 2 2160x1080 403 6.0 392.7dp 785.5dp
小米8 SE 2244x1080 424 5.88 360dp 748dp
小米8 2248x1080 402 6.21 360dp 749.3dp
小米8透明探索版 2248x1080 402 6.21 360dp 749.3dp
小米红米6 Pro 2280x1080 432 5.84 360dp 760dp

OPPO

机型 分辨率 ppi 尺寸 宽/density 高/density
OPPO A57 1280x720 282 5.2 360dp 640dp
OPPO A83 1440x720 282 5.7 360dp 720dp
OPPO A5 1520x720 271 6.2 360dp 760dp
OPPO R9S 1920X1080 401 5.5 360dp 640dp
OPPO R11 1920x1080 401 5.5 360dp 640dp
OPPO R11 Plus 1920x1080 367 6 360dp 640dp
OPPO R11s 2160x1080 401 6.0 360dp 720dp
OPPO R11s Plus 2160x1080 376 6.43 360dp 720dp
OPPO R15 2280x1080 402 6.28 360dp 760dp
OPPO A3 2280x1080 405 6.2 360dp 760dp
OPPO R17 2340x1080 402 6.4 360dp 780dp
OPPO Find X 2340x1080 401 6.42 360dp 780dp
OPPO R17 Pro 2340x1080 402 6.4 360dp 780dp

VIVO

机型 分辨率 ppi 尺寸 宽/density 高/density
vivo Y71 1440x720 269 6.0 360dp 720dp
vivo Y83 1520x720 270 6.22 360dp 760dp
vivo x7Plus 1920x1080 386 5.7 360dp 640dp
vivo X20Plus 2160x1080 376 6.43 360dp 720dp
vivo X20 2160x1080 401 6.0 360dp 720dp
vivo Y97 2280x1080 401 6.3 360dp 760dp
vivo X21屏幕指纹版 2280x1080 402 6.28 360dp 760dp
vivo X21 2280x1080 402 6.28 360dp 760dp
vivo Z1 2280x1080 403 6.26 360dp 760dp
vivo Y85 2280x1080 403 6.26 360dp 760dp
vivo NEX 2316x1080 388 6.59 360dp 772dp
vivo X23 2340x1080 402 6.4 360dp 780dp

魅族

机型 分辨率 ppi 尺寸 宽/density 高/density
魅族魅蓝S6 1440x720 282 5.7 360dp 720dp
魅族15 1920x1080 403 5.46 360dp 640dp
魅族PRO 7 1920x1080 424 5.2 360dp 640dp
魅族魅蓝Note 6 1920x1080 401 5.5 360dp 640dp
魅族16th 2160x1080 402 6 360dp 720dp
魅族16th Plus 2160x1080 372 6.5 360dp 720dp
魅族16 X 2160x1080 402 6.0 360dp 720dp
魅族15 Plus 2560x1440 494 5.95 360dp 640dp
魅族PRO 7 Plus 2560x1440 515 5.7 360dp 640dp

锤子

机型 分辨率 ppi 尺寸 宽/density 高/density
锤子科技Smartisan T2 1920x1080 445 4.95 360dp 640dp
锤子科技坚果Pro 1920x1080 401 5.5 360dp 640dp
锤子科技坚果Pro 2S 2160x1080 402 6.0 360dp 720dp
锤子科技坚果Pro 2 2160x1080 402 6.0 360dp 720dp
锤子科技坚果R1 2240x1080 403 6.17 360dp 746.7dp
相关文章
相关标签/搜索