程序员

Android屏幕适配与资源匹配

Android屏幕适配是个头疼的问题,同时关于这方面的讲解也是烂大街了,那么为什么还要写这篇博文呢,一方面是想基于Google官方教程和个人开发中的经验总结一份准确精炼的教程,另一方面也是作为一个知识备份。

那么,通过本文你可以学到以下这些:

1.Android界面开发中的那些名词的概念
2.如何和一名不懂Android的UI设计师合作
3.Android如何进行资源匹配

对应以下三块内容:

名词解释

px
px(pixel)即像素,没什么好说的,所有电子图形设备能够显示的最小粒度的单位,和尺寸什么的无关,一般设备每一个像素点都是一个正方形。我们常说的1080p或者2k屏就是指的像素。

inch
inch即英寸,没啥好说的,一般我们所说的几寸屏就是指的屏幕对角线是几英寸。Android曾经将屏幕尺寸组概括为四种:small、normal、large和xlarge,但是自Android 3.2(API=13)开始,这套尺寸组已弃用,而采用根据可用屏幕宽度管理屏幕尺寸的新技术。

dpi
dpi(dots per inch)即每英寸的像素点的个数,这个值可以表示屏幕密度。Android目前把所有的屏幕密度归纳为六种通用dpi:

ldpi ~120dpi
mdpi ~160dpi (baseline)
hdpi ~240dpi
xhdpi ~320dpi
xxhdpi ~480dpi
xxxhdpi ~640dpi

需要说明的是,上面的每种规格都只是圈定了一个范围,近似于后面的dpi数值,比如对于两台声明自己是hdpi屏幕密度的设备,其实际dpi值可能略有不同。此外,Android官方把mdpi定为基准(baseline),这个基准有什么用呢,后面就可以看到了。

density
density是真正意义上的屏幕密度,density=dpi/160,160是什么呢?正是我们上面说的基准mdpi的dpi值。在开发中可以由以下代码得到:

getResources().getDisplayMetrics().density;

dp
dp或dip(device independent pixels)即设备独立像素,Android特有的尺寸度量单位,设计的目的就是让其值在不同屏幕密度下能保持统一。在基准密度mdpi下,1dp=1px,因此dp和px的换算关系为dp=px/density=px*160/dpi

sp
sp(scaled pixels),可以大致翻译为比例像素,专门用于设置文字大小,其实其他和dp一样,唯一的不同就是会随着设备字体大小的设置项的改变而变化。

如何根据UI标注的px来开发

专业的UI设计师可能会给Android开发人员按照dp值来进行标注,并分几种不同的屏幕密度如hdpi、xhdpi来准备两套以上切图。但是很多“iOS系”的设计师会直接按照iPhone的模版来出图,并且按照iOS惯用的px来标注,然后发给一脸懵逼的我们。这个时候我们要去知道UI设计所采用的界面分辨率(720p?1080p?)是多少,当然最好也要知道目标设备屏幕尺寸是多少,比如同样是1080p,手机和平板的屏幕尺寸可是要差很大的。总而言之,我们是要确定依照哪种屏幕密度(hdpi?xhdpi?)来处理这套标注与切图。靠什么呢,靠下面这个主流机型屏幕尺寸表来映射吧(即使不知道具体的目标屏幕尺寸也没关系,只要知道你做的是手机还是平板应用就行了,然后基本上按照屏幕分辨率来选择吧)。

ldpi density=0.75
2.7″:240×320,3.3″:240×400,3.4″:240×432
mdpi density=1
3.2″:320×480,5.1″:480×800,5.4″:480×854
(Tablet)7.0″:1024×600,10.1″:1280×800
hdpi density=1.5
3.7″:480×800,3.7″:480×854,4.0″:480×800
xhdpi density=2
4.65″:720×1280,4.7″:720×1280,4.7″:768×1280
(Tablet)7.0″:1200×1920,8.9″:2048×1536,10.1″:2560×1600
xxhdpi density=3
5.0″:1080×1920
560dpi
5.7″:1400*2560

一般UI设计师在设计手机APP时,除了按照iPhone的尺寸来出图,可能比较常用的是720×1280或者1080×1920这两个分辨率,那么若是720x1280px,我们就可以直接按照xhdpi来将标注图上的px值转化为dp,dp=px/density=px/2,然后所有对应的切图也就不用犹豫,直接丢入到drawable-xhdpi里即可;同理,若是1080x1920px,按照xxhdpi来处理,等等。需要说明的是,很多网上的教程在屏幕适配方面建议每个尺寸的资源文件夹都放入一套资源文件,或者建议只准备一套hdpi的资源文件。这都不是很合理的,前者的话可能对于一些比较特殊或者重要的素材需要这样处理,否则的话这会大大增加apk文件的体积,因此对于要求不是特别高的情况,只准备一至两套即可,Android系统在显示图片的时候会根据自身dpi和素材所在drawable文件夹的dpi来自动进行放大或缩小;后者的话已经过时了,时代在进步,社会在发展,现在市场上的主流机型是大屏手机了,目前应该是xhdpi和xxhdpi为主流,因此在设计和准备图片资源的时候最好围绕这二者来做,当然,仅限于当下。

Android如何进行最佳资源匹配

在运行时,Android会检测当前设备配置并为应用加载合适的资源。那么Android如何去寻找它所认为的最合适的资源呢?假设有很多drawable目录分别包含相同图片资源的不同版本,那么参照以下流程图,匹配的过程如下:

Android资源匹配流程图

1.淘汰与设备配置冲突的资源文件
何谓与设备配置冲突的资源文件,这就不得不提到资源限定符了,比如我们默认生成的资源文件夹drawable-hdpi/中的hdpi就是一种限定符,实际上,限定符克不止屏幕像素密度这一种类型而是有很多,比如语言,屏幕方向,夜间模式,文本输入法,API级别等等十多种,如果要使用这些限定符则必须按照官方定义的规则去排序,比如drawable-en-port-xhdpi-12key/,顺序错误的话该资源文件夹会被忽略。理解了资源限定符这个概念,那么这一步就好理解了,那就是Android系统会根据当前设备的一系列配置去淘汰掉存在不匹配的资源限定符的文件夹,如语言不匹配或屏幕方向不匹配等等,但是要注意,屏幕像素密度是唯一一个不会因冲突而被淘汰的限定符。比如尽管设备的屏幕密度为hdpi,但是drawable-port-ldpi/不会被淘汰,因为此时每个屏幕密度均视为匹配。

2.双重循环(第一层遍历资源限定符,第二层遍历资源文件夹)
按照限定符的优先级顺序选取下一个限定符,然后查找是否有资源目录包含此限定符,都没有的话换下一个限定符,如果有的话淘汰掉不含该限定符的资源文件夹,在剩余的资源文件夹里再匹配下一个限定符。可想而知,一般情况下,通过这样一个双重循环匹配,最终会只剩一个资源目录,便是最合适的资源。不一般的情况往下看。

3.特殊情况
在步骤2中有一个例外,如果资源限定符的遍历走到了屏幕像素密度这一步,又没有完全匹配的资源文件夹,则Android会按比例缩小更高密度的资源或者放大更低密度的资源,比例系数为期望的dpi标准与实际的dpi标准的比值。就目前查找到的资料显示,通常,Android会选择一个能达到最佳效果的资源文件,因此它倾向于缩小大型原始图像,而不是放大小型原始图像。例如,设备是ldpi属性,但目前可用的资源文件有mdpi和hdpi版本,系统会优先选择缩小hdpi版本,因为系统可轻松以0.5为系数将hdpi资源缩小至ldpi资源,与以0.75为系数缩小mdpi中密度资源相比,伪影更少。此外,还有一点需要说明的是,系统会将drawable/ 中的资源作为“默认”资源,也就是指未标记配置限定符的资源,系统假设默认资源设计用于基线屏幕尺寸和密度,即mpdi,并在没有更合适的资源文件夹的情况下选择该文件夹中的资源,因此你的图片资源文件最好不要放置在该文件夹里,而是要放置在指定dpi的文件夹里。

Ref:
1.支持多种屏幕
2.提供资源

另,个人技术博客,同步更新,欢迎关注!转载请注明出处!文中若有什么错误希望大家探讨指正!

发表评论