由于设备的多样性,Android 系统会检测当前设备配置,并为应用加载合适(最匹配)的资源。下面根据经验结合官方api,详细说下系统适配的规则。
一、10种资源。在 res中以 <resources_name>-<config_qualifier> 形式命名目录。Android系统一共为应用提供了10类资源目录(即resources_name),如下表:
目录 | 资源类型 |
animator/ | 用于定义属性动画的 XML 文件 |
anim/ | 定义渐变动画的 XML 文件 |
color/ | 用于定义颜色状态列表 |
drawable/ | 位图文件(.png、.9.png、.jpg、.gif)、状态列表、形状... |
mipmap/ | 适用于不同启动器图标密度的 mipmap/ 文件夹管理启动器图标的详细信息。 |
layout/ | 用于定义用户界面布局。 |
menu/ | 用于定义应用菜单(如选项菜单、上下文菜单或子菜单)的 。 |
raw/ | 要以原始形式保存的任意文件(2.3版本要求1M)。 |
values/ | 包含字符串、整型数和颜色等简单值的 |
xml/ | 可以在运行时通过调用 Resources.getXML() 读取的任意 XML 文件 |
在IDE中如下图:
开发者需要根据不同的资源文件,放入对应的文件夹或者目录下,这里提下几个目录:
1.animator和anim一般都用来放动画,官方文档中说animator放属性动画,但其实动画统一放在anim也是没问题的,如果app动画不多,统一放在一个目录还便于管理。
2.Color通常防止颜色集合,这个跟value下面的颜色值要区分开来,value里面的color文件存放的是具体的颜色值,例如:
而color/防止的是颜色的状态列表,set集合
3.Raw里面,放置不需要编译成二进制的文件,与assets目录的区别就是,单个文件大小有约1m的限制,assets单个文件允许的大小要比raw大。另外,raw里面可以通过resource获取,assets里面的文件,只能通过assetmanager读取。
二、18种资源限定符。系统给app提供了上述10种resources_name后,还给大多数的资源,提供了18种限定符(config_qualifier)的支持,如下表:
优先级 | 配置 | 限定符值 |
1 | MCC | 移动国家代码,示例:mcc310、mcc310-mnc004、mcc208-mnc00等等 |
2 | 语言和区域 | 语言代码定义,示例:en、fr、en-rUS、fr-rFR、fr-rCA等等 |
3 | 布局方向(api-17) | 应用的布局方向,ldrtl 是指“布局方向从右到左”。ldltr 是指“布局方向从左到右”,这是默认的隐式值。 |
4 | smallestWidth(api-13) | 屏幕的基本尺寸,由可用屏幕区域的最小尺寸指定。sw<N>dp示例:sw320dp、sw600dp、sw720dp等等 |
5 | 可用宽度 | 指定资源应该使用的最小可用屏幕宽度。w<N>dp示例:w720dp、w1024dp等等 |
6 | 可用高度 | 指定资源应该使用的最小可用屏幕高度。h<N>dp示例:h720dp、h1024dp等等 |
7 | 屏幕尺寸 | small(320x426 dp)、normal(320x470 dp)、large(480x640 dp)、xlarge(720x960 dp) |
8 | 屏幕纵横比 | long(宽屏)、notlong(非宽屏) |
9 | 屏幕方向 | port、land |
10 | UI 模式 | car(车载手机座)、desk、television、appliancewatch |
11 | 夜间模式 | Night、notnight |
12 | 屏幕像素密度 (dpi) | ldpi、mdpi、hdpi、xhdpi、xxhdpi、xxxhdpi、nodpi、tvdpi |
13 | 触摸屏类型 | notouch:设备没有触摸屏、finger |
14 | 键盘可用性 | keysexposed:设备具有可用的键盘、keyshidden、keyssoft |
15 | 主要文本输入法 | nokeys:设备没有用于文本输入的硬按键、qwerty、12key |
16 | 导航键可用性 | Navexposed、navhidden |
17 | 主要非触摸导航方法 | Nonav、dpad、trackball、wheel |
18 | 平台版本(API 级别) | 示例:v3、v4、v7 等等 |
需要注意的是,相当一部分的资源限定符是在不同的系统api上逐步增加的,不要以为所有的系统版本都支持18中限定符,因此当你确定要添加该限定符时,应该要确保当前的api版本是否支持。
三、适配的原则:
当您请求要为其提供备用资源的资源时,Android 会根据当前的设备配置选择要在运行时使用的备用资源。规则如下:
1.淘汰与设备配置冲突的资源文件。
2.选择上述限定符表中优先级最高的限定符。(先从 MCC 开始,然后下移。)
3.是否有资源目录包括此限定符?
4.淘汰不含此限定符的资源目录。
5.返回并重复第 2 步、第 3 步和第 4 步,直到只剩下一个目录为止。
过程如下图:
四、一个sample:
上面说了规则,下面举个例子,假设设备配置如下:
区域设置 = en-GB
屏幕方向 = port
屏幕像素密度 = hdpi
触摸屏类型 = notouch
主要文本输入法 = 12key
有下面的资源去适配:
drawable/
drawable-en/
drawable-fr-rCA/
drawable-en-port/
drawable-en-notouch-12key/
drawable-land-hdpi/
drawable-port-notouch-12key/
1.根据四中的原则,第一步,淘汰与设备配置冲突的资源文件,因此下面的资源被淘汰:
drawable-fr-rCA/
drawable-land-hdpi/
2.第二、三步,选择限定符表中优先级最高的限定符,从mcc往下看,第一个mcc没有,第二个en,资源里面有目录包含有。
3.第四步,淘汰不含此限定符(en)的资源目录:
drawable/
drawable-port-notouch-12key/
4.第五步,重复上面的流程,port比notouch优先级高,所以淘汰
drawable/
drawable-en-notouch-12key/
5.最后,剩下
drawable-en-port/
这个就是系统的适配原则。
五、再说下drawable图片的适配,android系统是如何适配不同密度的手机呢,如下图:
如果要适配6中密度的手机,难道要放6套图片到各自的限定符目录中吗,这显然是不可能的,大小无法接受,通常情况是针对高屏幕密度(240dpi,一般对应分辨率为480x800)的手机,设计一套满足视觉效果的图片基本就能满足要求。
那么对于不落在这个密度范围内的手机,系统是如何适配的呢?
原则也很简单,系统会优先查找比当前密度更大的目录,看是否存在对应的图片,如手机为hdpi,若app里面hdpi目录下,没有图片,系统会依次查找xhdpi、xxhdpi、xxxhdpi的文件,如果仍然没有,再查找比他低密度的目录。
这样查找的好处在于,系统将使用比当前密度更大的图片来显示,防止图片拉伸变成锯齿。