当前位置: 代码迷 >> Android >> android手机屏幕适配有关
  详细解决方案

android手机屏幕适配有关

热度:147   发布时间:2016-04-24 11:28:22.0
android手机屏幕适配相关.
    以前总是看别人的blog,从来没自己写过.因为网上大牛太多,你知道的不知道的人家都写了.还写得特别好,要逻辑有逻辑,要文笔有文笔.这感觉类似像金庸写完14本武侠后,其它人的武侠再也跳不出其圈子.自己太懒.真要写点东西,文笔是一方面,另一个需要注意的就是要查阅大量的相关资料,因为毕竟是写出来给人看的.可以写的不完全,但一定不能有大错.

   写这篇文章是因为一个朋友问我,他写了一个demo,放了8张图片,每张只有5k.为什么就oom了.我一听就问他图片分辨率是多少.答案是700*500.我一听就告诉他你肯定是把图片只放在drawable文件夹里了.所以oom.然后告诉他解决方案时建个xxhdpi把图片丢进去.
后来他一试果然ok了.在告诉他这个oom错误的原理后,听到他很佩服的对我说"你真牛"时,心理还是有点暗爽的.其实他不知道,在上个星期因为我一次手贱,删掉了xxhdpi里的几张图片,也oom了,花了时间查资料才知道这个答案.后来收了收懒劲.把适配的相关都整理了一下.才有了这个文章.
   看别人的文章看得很爽,自己写真的觉得比敲代码难多了.改了错别字还要改语病.

一 适配相关单位说明
像素pix: 屏幕的最小显示单元
分辨率: 区域内的像素数量,分辨率相同时屏幕尺寸越小越清晰
屏幕尺寸: 屏幕的对角线长度,单位为英寸.
像素密度DPI: 每英寸的屏幕的像素数量.密度越高,细节越丰富.
DPI计算方式为屏幕对角线的像素数除以尺寸. 简化算法为分辨率的宽2+2/屏幕尺寸2
Dp或Dip: android定义的一个尺寸单位,与密度无关的抽象像素.以当dpi为160时1dp=1px

DP是一种绝对的物理的尺寸定义,DP的作用是让同一数值在不同的分辨率下展示出大致相同的物理尺寸

Density: 转换比例.DP和PX之间的比例.在dpi 160时Density =1,也就是Density=Dpi/160;


    那么1dp到底有多少呢??在标准屏幕密度下,1英寸有160px,这时1px=1dp,也就是说1英寸有160dp.那么1dp=1/160英寸.1dp=2.54厘米/160=0.15875毫米.

    在android中无论什么样密度的屏幕,100dp永远全显示出近似15.875毫米的长度.因此造成的问题就是在不同屏幕尺寸下,同样DP的组件所占据的屏幕比例是不同的.

在java代码里使用的单位全是px,而xml中使用的都为dp

二 android的适配策略
在android中定义了几个DPI适配级别 ,用与适配不同的dpi和分辨率,还有一个xxxhdpi为640DPI


ldpi
mdpi
hdpi
xhdpi
xxhdpi
DPI120
160
240
320
480
分辨率240*320
320*480
480*800
720*1280
1920*1080
Density0.7511.523

系统分根据这五种级别进行适配

1 加载资源文件会屏幕的相关信息去查找合适的文件夹,如没有最后会加载默认的资源文件夹中的资源.
2 常用的资源分两种,drawable和values.默认文件夹为无后缀的drawable和values 默认为mdpi

3 适配用的文件夹后缀.根据优先极分为  

   smallestWidth(sw<N>dp)>可用宽度(w<N>dp)>可用高度(h<N>dp)>屏幕尺寸(normal)>屏幕像素密度 (hdpi)>分辨率(1280*720)

   后缀的格式为 drawable-xxxx-xxx 可以多个后缀同时存在,但必须按优先级的顺序排列.
a smallesWidth 最小尺寸:如sw480dp,这是个坑宽爹的属性.最小是不管宽或高的.所以基本没用.
b 可用宽度:如as创建项目时自带的w820dp.系统会匹配与屏幕宽度最接近并小与等与屏幕宽度的文件夹.
c 可用高度:如h820dp 同可用宽度
对与这两种后缀.屏幕在横竖屏切换时会读不同的配置.
d 屏幕尺寸:这是API 4以后出来的新属性,括号内为此级别的屏幕最小尺寸要求.有small(320x426 dp ),normal( 320x470 dp),large(480x640 dp),另外API 9增加了xlarge(720x960 dp).
屏幕像素密度(DPI),这个就不用说了见上表.xhdpi要求API 8,xxhdpi要求API 16,API 18新增xxxhdpi(640dpi).

f 分辨率.这个后缀并不存在与官方文档中.但实际上是存在的.写法为-1280x720 数值大的放在前面.(这个看起来很好.但实际上匹配起来也有坑,后面会说到).  

三 drawable的匹配策略
1 系统会根据读取的资源文件夹的Density和屏幕Density的比例进行缩放.比如屏幕320dpi,如果是从默认文件夹里读取一个30px*30px的图片.实际上会放大成 60*60的图片读取到内存中.
2 如果系统找不到最匹配的配置时会使用默认的配置.但不总是会读取默认配置.实际上系统在读取drawable时的匹配是以缩放的效率来决定的.
   比如匹配ldpi,系统会优先选择hdpi而不是mdpi.因为缩小一半比缩小3/4要效率
   同理,在匹配xxhdpi时系统会优先选择mdpi(默认)而不是xhdpi(这是个人根据上面的例子进行的推论,在缩放时系统倾向与缩小还是放大这点还不明确)
四 values的匹配策略

1 hdpi 匹配:通过屏幕自身的Dpi和分辨率来查找相应的后缀为?hdpi的资源文件夹.如果Dpi不能完全对应,则看分辨率.

   最明显的例子是华为的Mate8 367的Dpi更接近xhdpi,但因为分辨率1080P完全匹配xxhdpi.所以从xxhdpi中读取资源     

    dpi的匹配顺序是先查找完全匹配的文件夹,如果没有,则向大一级的dpi匹配;如果没有比自身大的dpi,则会向小一级的dpi匹配。最后才匹配values文件夹

    原来的认识是没有匹配会像小一级的dpi匹配,结果http://2kpurple.github.io/2014/08/14/Android-values-folder/这篇文章证明了事践才是检验真理的最高标准.
2 分辨率匹配:这个也有个坑.屏幕适配是按app的屏幕尺寸来适配的.注意是app的屏幕尺寸.当初android在决定这个适配策略时没有想到几年后他们会搞出一个叫虚拟按键的东东..
   所以分辨率匹配在有虚拟按键的手机上会有坑.例如Galaxy Nexus(1280x720 ),却可以匹配到values-hdpi-1024x600

3 屏幕尺寸匹配:以前从来都不知道还有这个东东.优先度还比dpi高.然而卵并卵.large这个东西兼容性太强.在当今天主流的各种手机面前,毛用都没有.

四 主流屏幕的相关参数

对角线的px  1080p=2203px,720p=1468px

屏幕尺寸(英寸)
分辨率
DPI
 Density(转换率 )
宽度DP
高度DP
读取资源
6.0
1080p
3672.5432768xxhdpi
5.5
1080p
4003360640xxhdpi
5.2
1080p
4233360640xxhdpi
5.0
1080p
4403360640xxhdpi
4.7
720p
3122360640

xhdpi

非主流 三星S7.

5.12k(2560x1440)5763.5(计算值)441731xxxhdpi(推测 )

    都说安卓碎片化严重.但表格出来后,发现还是很合谐的.360dp*640dp占据了主流.xxhdpi可以说占领了大半江山.可以说现在是屏幕适配最好的时候. 

    从这个表可以看到,从5.0-5.5.都是360Dp的宽度.证明以上每一种屏上的1Dp长度并不是完全相同,而是近似相同.

    当然.坑爹的不是没有.  

    Mate8是个很神奇的机型.367的dpi.2.5的density是个很坑爹的存在.没有任何drawable文件夹能完全匹配.读取一个1080p的图片时会缩小成1600*900加载到内存中.如果想不缩放,只能用nodpi.但nodpi的匹配优先级是最低的.试过-sw430dp-nodpi,依然不起作用.

   现在主流的5-5.5/1080P也是个很奇怪的配置.400的dpi无论怎么算density都应该是2.5而不是3...  

非主流的S7的出现标志着2k屏甚至4k屏开始出现在手机上了.xxxhdpi以后肯定会有一席之地.xhdpi会慢慢退出手机界.

五 总结

1 drawable 应用中完全有可以只用两套,甚至一套图.xxhdpi是必不可少的.xhpi可以考虑让系统去缩小xhdpi的图.至与要不要为S7去配个xxxhdpi,考虑到中国棒子粉特别多,还是搞一套吧.其它的就可以不用放了.drawable里可以只放shape

2 values 准确来说应该是dimens.这个比drawable麻烦些.大多是准备几套dimens.设定一套为基础比如padding=16dp,另一套根据Density进行缩放,如padding=24dp.这种做法从本质上来讲是为了尽量保证比例. 

但还是有问题.

一 难免会遇到个别机型会乱读dimens.

二  有时候同比缩放并不招人喜欢.比如字体大小.

三 坑爹的虚拟按键,把屏幕从16:9变成了差不多4:3.有时同样的布局放上去有种范冰冰变凤姐的感觉. 

3 知道了基础和原理,屏幕适配其实也很容易.最大放小,匹配大多数. 最好的适配方式就是把UI妹子拉到自己身边,一边聊天,一边微调.最后屏幕适配好了.妹子也不远了.                              


最后附上官方说明文档.翻译得一般.比机翻强半分钱.仅作参考

At runtime, the system ensures the best possible display on the current screen with the following procedure for any given resource:

运行时,系统确保尽可能的按照下流程获取给定的资源显示当前屏幕上.

  1. The system uses the appropriate alternative resource

    Based on the size and density of the current screen, the system uses any size- and density-specific resource provided in your application. For example, if the device has a high-density screen and the application requests a drawable resource, the system looks for a drawable resource directory that best matches the device configuration. Depending on the other alternative resources available, a resource directory with thehdpi qualifier (such as drawable-hdpi/) might be the best match, so the system uses the drawable resource from this directory.

    系统使用适当的替代资源

    基于当面屏幕的尺寸和密度,系统使用由你的应用提供的任何尺寸和密度特性的资源.例如,如果设备是高密度的屏幕而应用需要drawable资源,系统会去寻找与设置配置最匹配的drawable资源文件夹.

    在可获得的资源中,一个hdpi级别(例如drawable-hdpi/)的文件夹可能是最匹配的.这样系统就会使用这个文件夹里的资源.

  2. If no matching resource is available, the system uses the default resource and scales it up or down as needed to match the current screen size and density

    The "default" resources are those that are not tagged with a configuration qualifier. For example, the resources in drawable/ are the default drawable resources. The system assumes that default resources are designed for the baseline screen size and density, which is a normal screen size and a medium density. As such, the system scales default density resources up for high-density screens and down for low-density screens, as appropriate.

    However, when the system is looking for a density-specific resource and does not find it in the density-specific directory, it won't always use the default resources. The system may instead use one of the other density-specific resources in order to provide better results when scaling. For example, when looking for a low-density resource and it is not available, the system prefers to scale-down the high-density version of the resource, because the system can easily scale a high-density resource down to low-density by a factor of 0.5, with fewer artifacts, compared to scaling a medium-density resource by a factor of 0.75.

    如果没有可获得的匹配资源.系统会使用默认的资源并且根据当前的屏幕尺寸和密度进行缩放.
    这个默认的资源是没有标记配置的.例如drawable/文件夹就是个默认的drawable资源.系统把默认的资源设计成基础的屏幕尺寸和密度.使用的是noraml尺寸和medium密度.省略了后缀显示.系统会以默认的密度去根据目标屏幕的密度去进行缩放处理.
    然而.当系统去寻找一个指定密度尺寸的资源时没有找到对应的资源文件夹,不会总是使用默认的资源.  当缩放时系统可能使用另一个特定密度的资源,以提供更好的结果.例如.当寻找一个low密度(ldpi 120dpi)的资源但没有找到.系统更愿意去缩小一个high密度的资源.相比把一个midium密度(mdpi 160dpi)的资源缩小到0.75,系统把一个high密度(hdpi 240dpi)缩小到0.5会更容易.

参考文章:http://developer.android.com/intl/zh-cn/guide/practices/screens_support.html

                 http://developer.android.com/intl/zh-cn/guide/topics/resources/providing-resources.html

                 http://2kpurple.github.io/2014/08/14/Android-values-folder/

                 http://bugly.qq.com/bbs/forum.php?mod=viewthread&tid=498&extra=page%3D1(这个文章很值得一读)




  相关解决方案