提供可选的替代资源
乎每个应用程序都应该提供可选的替代资源,来支持特殊的设备配置。例如,应该针对不同的屏幕分辨率来包含可选的可描画资源,并且为不同的语言环境提供可选的字符串资源。在运行时,Android系统会检测当前设备配置,并给应用程序加载合适的资源。
以下是给特殊配置指定一组可选资源的步骤:
1. 用<resources_name>-<config_qualifier>的格式在res/目录中创建一个新的目录,<resources_name>是对应的默认资源的目录名(表1中定义的);<qualifier>是给使用这些资源的设备所指定的一个单独配置的名字(表2中定义的)。每个名称可以用短划线来添加多个<qualifier>
警告:在添加多个限定符时,必须按照表2中列出的顺序来放置它们。如果限定符的顺序错了,资源就会被忽略。
2. 在这个新的目录中分别保存可选的替代资源。这些资源文件必须像默认资源文件一样被准确的命名。
例如,以下是默认和可选资源的定义:
res/
drawable/
icon.png
background.png
drawable-hdpi/
icon.png
background.png
hdpi限定符指示这个目录中资源是给高分辨率屏幕使用的。每个可描画目录中图片都是为特定分辨率的屏幕准备的,但是它们的文件名是完全相同的。这样用于引用icon.png和background.png图片的资源ID就会相同,Android系统会通过设备配置信息和资源目录名中的限定符的比较结果,来选择跟当前设备匹配最好的资源版本。
Android支持几种配置限定符,并且可以在一个目录名中通过用短划线的分隔,来添加多个限定符。表2按照优先的顺序列出了有效的配置限定符,如果要在资源目录中使用多个限定符,一定要按照表2列出的顺序把它们添加到目录名中。
表2.配置限定符名称
配置 |
限定符值 |
说明 |
MCC和MNC |
例如: mcc310 mcc310-mnc004 mcc208-mnc00 等 |
MCC是移动国家代码的英文首字母缩写(The mobile country code),它的后面可选择性的跟随来自设备内的SIM卡的移动网络代码(MNC:mobile network code)。如在任何载体上,mcc310代表美国,mcc310-mnc004代表美国的Venizon公司,mcc208-mnc00代表法国的Orange公司。 如果设备使用音频连接(GSM 电话),那么MCC和MNC的值来自SIM卡。 也可以单独使用MCC(例如,在应用程序中包含特殊国家合法的资源)。如果仅需要指定语言环境,那么可以使用language和region限定符来替代(稍后讨论)。如果决定要使用MCC和MNC限定符,就要仔细测试,使它能够满足你所期望的工作。 还可以查看配置域mcc和mnc,它们分别指示了当前的移动国家代码和移动网络代码。 mcc:http://developer.android.com/reference/android/content/res/Configuration.html#mcc mnc:http://developer.android.com/reference/android/content/res/Configuration.html#mnc
|
语言和地区 |
例如: en fr en-rUS fr-rFR fr-rCA |
语言是用两个字母的ISO 639-1语言代码定义的,紧跟其后的是可选的两个ISO-3166-1-appha-2地区代码字母(前面是小写的“r”)。 这个编码不区分大小写,r前缀被用于区分地区部分,不能够单独指定地区。 如果用户改变了系统中的语言设置,那么在应用程序的运行期间也能够改变为对应的语言。 |
最小宽度 |
sw<N>dp 例如: sw320dp sw600dp sw720dp 等 |
屏幕的基本尺寸,是指最短的可用屏幕区域。具体的说,设备的最小宽度是屏幕可用的宽度和高度中最短的那个(也可以把它看做是屏幕的最小可能的宽度)。这样就可以使用这个限定符来确保应用程序至少有<N>dp的宽度可用于UI界面,而不管屏幕的当前方向。 例如,如果布局在任何时候都需要至少600dp的最小屏幕尺寸,那么就能够使用这个限定符,在res/layout-sw600dp/目录中创建布局资源。系统只会在可用屏幕的尺寸至少是600dp的时候才会使用这些资源,而不管600dp是否是被用户认知的高度或宽度。最小宽度是设备的固定屏幕尺寸特征,当屏幕的方向发生改变时,设备的最小宽度不改变。 设备的最小宽度需要考虑屏幕的装饰和系统UI的占用。例如,如果设备有一些固定的UI元素要沿着最小宽度的轴向,占用一定的屏幕空间,那么系统声明的最小宽度要比实际的屏幕尺寸要小,因为被系统占用的像素部分对用户应用程序的UI无效。因此,这个值应该是应用程序布局所需要的最小的实际尺寸(通常,这个值是布局支持的最小宽度,而不管屏幕的当前方向)。 以下是可以使用的通用屏幕尺寸的一些值: 1.320,针对以下屏幕配置的设备: 240x320ldpi(QVGA手持设备) 320x480mdpi(手持设备) 480x800hdpi(高分辨率手持设备) 2.480,针对480x800mdpi的屏幕(平板或手持设备) 3.600,针对600x1024mdip的屏幕(7英寸平板) 4.720,针对720x1280mdip的屏幕(10英寸平板) 当应用程序提供了多个带有不同值的最小宽度限定符资源目录时,系统会使用最接近(不超出)设备最小宽度的那个资源。 这个限定符被添加在API级别13中。 还要看android:requiresSmallestWidthDp属性,它声明了与你的应用程序兼容的最小的最小宽度,并且smallestScreenWidthDp配置字段会持有这个设备最小宽度的值。 |
可用宽度 |
w<N>dp 例如: w720dp w1024dp 等 |
指定最小的可用屏幕宽度,在资源中应该以dp为单位来定义<N>的值。当方向在横向和纵向之间改变时,这个配置值会跟当前的实际的宽度相匹配。 当应用程序给这个配置提供了多个不同值的资源目录时,系统会使用最接近(不超过)设备当前屏幕宽度的那个配置。这个值需要考虑屏幕装饰占据的空间,因此,如果设备在显示的左边或右边有一些固定的UI元素,那么使用的宽度值就要比实际的屏幕尺寸小,因为这些固定UI元素的占用,使得应用程序的可用空间减少。 这个特性被添加在API级别13中 还要看screenWidthDp配置字段,它持有当前的屏幕宽度。 |
可用高度 |
h<N>dp 例如: h720dp h1024dp 等 |
指定最小的可用屏幕高度,在资源中应该以dp为单位来定义<N>的值,当方向在横向和纵向直接改变时,这个配置值应该跟当前的实际高度匹配。 当应用程序给这个配置提供了不同值的多个资源目录时,系统会使用最接近(不超过)设备当前屏幕高度的那个配置。这个要考虑屏幕装饰的占用情况,因此,如果设备在显示的上方或底部有一些固定的UI元素,那么要使用的高度值要比实际的屏幕尺寸小,因为这些固定UI元素的占用,使得应用程序的可用空间减少。不固定的屏幕装饰(如电话的状态栏能够在全屏时被隐藏)是不考虑的,像标题栏或操作栏这样的窗口装饰也不考虑,因此应用必须准备处理比它们指定的空间要小的情况。 这个限定符被添加在API级别13中。 还要看screenHeightDp配置字段,它持有当前屏幕的高度。 |
屏幕尺寸 |
small normal large xlarge |
small:这种屏类似低分辨率的QVGA屏幕。对于小屏的最小布局尺寸大约是320x426dp。例如QVGA低分辨率和VGA高分辨率。 normal:这种屏类似中等分辨率的HVGA屏幕。对于普通屏幕的最小布局尺寸大约是320x470dp。如,WQVGA低分辨率屏、HVGA中等分辨率屏、WVGA高分辨率屏。 large:这种屏类似中等分辨率的VGA屏幕,对于大屏幕的最小布局尺寸大约是480x640dp。例如VGA和WVGA的中等分辨率屏。 xlarge:这种屏被认为比传统的中等分辨率的HVGA屏幕大。针对xlarge屏的最小布局尺寸大约是720x960dp。在大多数情况下,这种超大屏幕的设备因为太大而要放到背包中来携带,而且最有可能的是平板样式的设备。 注意:使用尺寸限定符不意味着资源仅用于这个尺寸的屏幕。如果没有用限定符提供与当前设备配置相匹配的可选资源,那么系统会使用与配置最接近的资源。 警告:如果所有使用尺寸限定符的资源都比当前屏幕大,那么系统将不会使用它们,并且应用程序会在运行时崩溃(例如,如果所有的布局都被标记了xlarge限定符,而设备却是一个普通尺寸的屏幕)。 这个限定符被添加在API级别4以后的版本中。 |
屏幕外观 |
long notlong |
long:长屏幕,如WQVGA、WVGA、FWVGA notlong:非长屏幕,如QVGA、HVGA、VGA 这个限定符被添加在API级别4以后的版本中 这个限定符完全是基于屏幕的外观比率,不相对屏幕的方向。 还要看screenLayout配置字段,它指示了屏幕是否是长屏。 |
屏幕方向 |
port land |
port:纵向设备(垂直) land:横向设备(水平) 如果用户旋转屏幕,这个限定能够在应用程序运行期间改变。 orientation配置字段指示当前设备的方向。 |
泊位模式 |
car desk |
car:设备停靠在汽车中 desk:设备停靠在书桌中 这个限定符被添加在API级别8以后的版本中 如果用户改变了设备的停靠地点,那么能够在应用程序的运行期间改变这个限定。可以使用UiModeManager对象来启用或禁止这种模式。 |
夜间模式 |
night notnight |
night:夜间 notnight:白天 被添加在API级别8以后的版本中 如果夜间模式被保留在自动模式中(默认),那么在应用程序运行期间,会基于白天的时间来进行模式的改变。可以使用UiModeManager对象来启用或禁止这种模式。 |
屏幕像素密度(dpi) |
ldpi mdpi hdpi xhdpi nodpi tvdpi |
ldpi:针对大约120dpi的低分辨率屏幕; mdpi:针对大约160dpi的中等分辨率屏幕(在传统的HVGA上); hdpi:针对大约240dpi的高分辨率屏幕; xhdpi:针对大约320dpi的超高分辨率屏幕,被添加在API基本8以后的版本中; nodpi:这个限定被用于不想根据匹配的设备分辨率进行缩放的位图资源。 tvdpi:在mdpi和hdpi之间的屏幕,大约是213dpi。这种分组不是主要的分辨率,大多数是为电视来考虑的,并且大多数应用不需要它---提供mdpi和hdpi资源就可以满足大多数应用程序需要了,并且系统会适当的缩放它们。这个限定符在API级别13以后被引入。 四种主要的分辨率之间的缩放比例是:3:4:6:8(忽略tvdpi分辨率),因此一个9x9的ldpi位图,在mdpi中是12x12、在hdpi中是18x18、在xhdpi中是24x24。 如果感觉在电视或其他某些设备上的图片资源不好看,并且想要试用tvdpi资源,那么缩放因子是1.33*mdpi。例如,一个100px x 100px的mdpi图片的图片应该被放大成133px x 133px的tvdpi图片。 注意:使用分辨率限定符不意味着资源仅适用与对应分辨率的屏幕。如果没有提供与当前设备配置匹配的可选资源,那么系统会使用最接近的资源。 |
触屏类型 |
notouch stylus finger |
notouch:非触屏设备 stylus:有适用手写笔的电阻屏设备 finger:触屏设备 touchscreen配置字段,指示到了设备上的触屏类型。 |
键盘可用性 |
keysexposed keyshidden keyssoft |
keysexposed:设备有可用的键盘。如果设备启用了软键盘,那么即使在硬键盘没有暴露给用户时也可以使用这个限定符。如果没有提供软键盘或者软键盘被禁用,那么只有在硬键盘被暴露给用户时才能够使用这个限定符。 keyshidden:设备有可用的硬键盘,但是被隐藏了,并且设备没有可用的软键盘。 keyssoft:设备有可用的软键盘,不管它是否可见。 如果提供了keysexposed资源,但没有keyssoft资源,那么只要系统有可用的软键盘,系统就会使用keysexposed资源而不管键盘是否可见。 如果用户打开了硬键盘,就可以在应用程序运行期间改变这个限定。 hardKeyboardHidden和keyboardHidden配置字段分别指明硬键盘的可见性以及可见的键盘类型(包括软键盘)。 |
主要文本输入法 |
nokeys qwerty l2key |
nokeys:设备没有用于文本输入的硬键盘; qwerty:设备有标准的硬键盘,不管用户是否可见; 12key:设备有12个键的硬键盘,不管用户是否可见。 keyboard配置字段指明可用的主要文本输入方法。 |
导航键的有效性 |
navexposed navhidden |
navexposed:导航键对用户可用; navhidden:导航键不可用。 如果用户能够看到导航键,那么在应用程序运行时就能够改变这个限定。 navigationHidden配置字段,指示导航键是否隐藏。 |
主要的非触屏导航方法 |
nonav dpad trackball wheel |
nonav:除了使用触屏以外,设备没有其他导航设施。 dpad:设备有用于导航的定向板(d-pad)。 trackball:设备有用于导航的轨迹球。 wheel:设备有用于导航的定向滚轮(不常见)。 navigation配置字段指明可用的导航方法类型。 |
平台版本(API 级别) |
例如: v3 v4 v7 等 |
设备支持的API级别。如v1代表API级别1(带有Android1.0或更高版的设备),v4代表API级别4(带有Android1.6或更高版本的设备) 警告:Android1.5和1.6只有在限定符跟平台版本完全匹配时,才能匹配资源。 |
注意:某些配置限定符从Android1.0开始就被添加了,因此不是所有的Android版本都支持所有的限定符。使用一个新的限定符,就隐含着添加了平台版本限定符,这样旧的设备才能够保证忽略这个限定符。如使用w600dp限定符,将自动的包含v13限定符。因为有效宽度限定符在API级别13以后才支持。要避免一些问题的发生,就要始终包含一组默认的资源(这组资源没有限定符)。
限定符命名规则
以下是有关使用配置限定符的命名规则:
1. 能够给单一的资源集合指定多个限定符,限定符用短横线分开。例如,drawable-en-rUS-land指定资源要用于横向的美式英语设备。
2. 限定符必须按照表2列出的顺序来使用,如:
错误用法:drawable-hdpi-port
正确用法:drawable-port-hdpi
3. 可选资源目录不能嵌套,如:不能用以下这样的目录结构:
res/drawable/drawable-en/
4. 值是大小写敏感的。资源编译器为了避免有关大小写敏感的文件系统问题,会把目录名转换成小写。命名中的任何大写字母只是为了方便阅读。
5. 每个限定符类型只能支持一种资源值。例如,如果想对西班牙和法国使用同一个可描画文件,不能把目录名命名成drawable-rES-rFR/。相反需要两个目录,如:drawable-rES和drawable-rFR/,每个目录中包含对应的文件。但是实际上不需要在这两个目录中复制相同的文件,可以使用资源命名别名来解决,详细请看下面的“创建资源别名”。
把这些可选资源保存到这些带有限定符的命名目录中后,Android会基于当前的设备配置在应用中自动的应用相应的资源。每次请求资源,Android都会检查包含请求资源文件的可选资源目录,然后查找最匹配的资源。如果没有跟实际设备配置匹配的可选资源,那么,Android会使用相应的默认资源(不包含配置限定符的一组资源)。
给资源创建别名
当要给多种设备配置使用同一个资源时(但不打算把这个资源作为默认资源),不需要把相同的资源放在多个可选资源目录中,相反,在某些情况下,能够像保存在默认资源目录中一样给可选资源创一个别名。
注意:不是所有的资源都提供能够创建一个指向另外一个资源的别名的机制。实际上,animation/、menu/、raw/以及xml/目录中的非特定资源不提供这中功能。。
例如,假设有一个应用程序图标:icon.png,它在不同的地区需呀唯一的版本。但是,有两个地区,加拿大英语去和加拿大法语区,它们需要使用相同的版本。可以假设需要把相同的图片分别复制到加拿大英语区和加拿大法语区的资源目录中,但实际上不需要这么做。可以把使用icon_ca.png名字来保存这张图片(icon.png以外的任意名称),并且把它放到默认的res/drawabel/目录中,然后在res/drawable-en-rCA/和res/drawable-fr-rCA/目录中创建一个cion.xml文件,使用<bitmap>元素指向icon_ca.png资源。这样就允许只保存一个版本的PNG文件,并且有两个小的XML文件指向它。
可描画资源别名
使用<bitmap>元素,给一个既存的可描画资源创建一个别名,例如:
?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/icon_ca" />
如果把这个文件作为icon.xml来保存在一个可选资源目录中,如res/drawable-en-rCA/,那么它就会被编译进能够使用R.drawable.icon来引用的资源,但是实际上它是R.drawable.cion_ca资源的一个别名。
布局资源别名
使用封装在<merge>元素中的<include>元素来给一个既存的布局创建别名,如:
<?xml version="1.0" encoding="utf-8"?>
<merge>
<include layout="@layout/main_ltr"/>
</merge>
如果把这个文件保存为main.xml,那么它就会被编译进能够用R.layout.main来引用的一个资源,但是实际上它是R.layout.main_ltr资源的别名。
字符串和其他简单值的资源别名
只需简单的使用被期望的字符串的资源ID作为新的字符串的值,就可以给一个既存的字符串创建一个别名,如:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello</string>
<string name="hi">@string/hello</string>
</resources>
R.string.hi资源现在是R.string.hello资源的一个别名。
其他简单的值资源也是用同样的方法,如一个颜色值:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="yellow">#f00</color>
<color name="highlight">@color/red</color>
</resources>