Android如何给不同配置机器引入对应的资源文件

鉴于本人英语能力有限,所以很多地方翻译只能翻译个大概,如果有错误欢迎大家指正~


我们都知道开发Android App的时候会把像字符串、图片、布局框架等资源携程xml放在res目录中然后在程序中去引用。

但是如果我们只提供一套资源文件,有时候碰到硬件配置不大相同的设备(比如屏幕的大小不同),显示就会出现差异,比如有些小图片在大屏幕设备上会变得很模糊。


为了让我们的图片等资源文件在各种Android设备中都能正常显示,我们就必须为不同配置的设备准备一套资源文件。

首先来看一下 资源文件目录 的大致结构:

MyProject/
    src/  
        MyActivity.java  
    res/
        drawable/  
            icon.png  
        layout/  
            main.xml
            info.xml
        values/  
            strings.xml  

可以看到所有的资源文件都在 res/ 目录中,而不同类型的资源文件又放在不同名字的目录里,像icon.png这样的图片都放在res/dawable/ 中,像main.xml、info.xml这样的布局框架都放在res/layout/ 中,像strings.xml这样的字符串相关的东西可以放在 res/values/ 中。


也就是说,资源文件都是分类存放的,不同类型的资源文件会放在与之类型相关的目录中(从目录名就可以看出是否与其类型相关)。


下面给出官方Android开发者网站API文档中列出的 res/ 中可以存在的一些目录:

目录名 资源类型
animator/ 里面存放定义了 property animations 的xml文件。
anim/ 里面存放定义了 tween animations.的xml文件。 (Property animations 也能存在这个目录里, 但是定义在 animator/ 目录中更容易区分这两种类型)
color/                                                    里面存放定义了Color State List(颜色状态表) 的xml文件。
drawable/

里面存放定义了如以下类型的位图 (.png.9.png.jpg.gif) 或xml文件:

  • Bitmap files (位图文件)
  • Nine-Patches (可拉伸的图片,一般是以".9.png"为后缀的图片文件) 
  • State lists (状态列表,比如color state list)
  • Shapes (形状)
  • Animation drawables (动画)
  • Other drawables (其他的可绘文件)

更详细的可以参考官方文件: Drawable Resources.

layout/ 里面存放定义的UI布局(layout)的xml文件. 不明白什么是layout,可以参考 Layout Resource.
menu/ 里面存放定义了菜单的xml文件,例如Options Menu, Context Menu, or Sub Menu(我的博客里也有关于这三个控件的使用介绍). 想了解menu控件可以参考 Menu Resource.
raw/ (没用过,暂时先不翻译这个)

Arbitrary files to save in their raw form. To open these resources with a raw InputStream, callResources.openRawResource() with the resource ID, which is R.raw.filename.

However, if you need access to original file names and file hierarchy, you might consider saving some resources in the assets/ directory (instead of res/raw/). Files in assets/ are not given a resource ID, so you can read them only using AssetManager.

values/

里面存放一些常量值,例如一些字符串、颜色的值、整数值等。

在的 res/ 的其他目录中,一个xml文件定义了一个资源,但是在 values/ 目录中一个xml文件可以定义许多资源。 更详细的讲,在一个xml文件中会有一个 <resources>标签,在这个标签里的所有子标签都定义了一个资源。举个例子:

<resources>
    <string name="str1">翻译老辛苦了 T。 T </string>
    <string name="str2">大家给点评论</string>
    <string name="str3">我才有动力。。。</string>
<resources>

可以看到每个<string>标签都定义了一个字符串资源。

在这个目录中每个xml文件分别代表了一种资源的类型,例如字符串资源都要定义在strings.xml文件中,而颜色值都要定义在color.xml中,下面列出了 values/ 中可以存在的一些xml文件名:

  • arrays.xml 用于定义数组资源(如string-array等)
  • colors.xml 用于定义颜色值资源
  • dimens.xml 用于定义尺寸资源
  • strings.xml 用于定义字符串资源
  • styles.xml 用于定义风格资源

更多详情请参考 String ResourcesStyle Resource 和 More Resource Types

xml/ 里面存放能够在程序运行时通过调用Resources.getXML()来读取的xml文件。各种xml配置文件必须存放在这里,,比如searchable configuration.

※注意:绝对不能在 res/ 目录中直接存放资源文件,否则会造成编译错误!!!!!





好了,那么关于资源文件组织的结构到这里就差不多搞清了,那么接下来就讲讲如何为不同配置的设备提供可选的资源。

刚才我们提到了不同类型的资源会被存储在有相应目录名的目录中,那么如果要为某些指定的设别提供相应的资源,只需按如下两点来设置:

(1)  在 res/ 中创建新的目录,目录的名字要按照 "<资源类型>+<限定符>" 的格式来命名。例如:drawable-hdpi 是针对高像素密度的设备,drawable-ldpi 是针对低像素密度的设备。

<资源类型>是上面那张表格中的任意值,用来指定资源类型。

<限定符>是下面这张表格的任意值,用来指定我们要针对设备的一些配置参数。限定符可以设定多个,用减号(-)来隔开,但是必须按照下面的表格中出现的顺序来排序!!!


(2)  不加限定符命名的目录会被系统认为是资源加载的默认目录,我们需要在我们的新目录中存放另一份适合其配置的资源文件,而且这个资源文件的名字要和在默认目录中的对应的资源文件的名字一样!!!!


下面给出官方Android开发者网站API文档中列出的可以使用的限定符:

要限定的内容  可用的限定符 描述
移动电话国家代码和移动电话网络代码(MCC、MNC)                                                                                                                                                              例如:
mcc310
mcc310-mnc004
mcc208-mnc00
等.

表示从设备的SIM卡中读取的移动电话国家代码(MCC)或移动电话网络代码(MNC)。举个例子:mcc310 代表美国, mcc310-mnc004 代表美国威瑞森公司,而 mcc208-mnc00 法国的橙子公司。

如果设备使用无线信号连接 (GSM 手机), 那么MCC和MNC代码是来自手机中的SIM卡。

你也可以只单独使用MCC (例如:你要在你的应用中加入针对特定国家的资源文件)。不要用这个限定符来指定语言,如果要针对某些语言,请使用"Language and region"限定符。

语言和地区(Language and region) 例如:
en
fr
en-rUS
fr-rFR
fr-rCA
等.

设定语言的限定符由两个字母构成,在 ISO 639-1 中可以查看所有可选的值,可以参见左边小格中给出的如 en、fr 等例子。语言限定符后面可以附带(可选) ISO 3166-1-alpha-2 中定义的地区代码 (用小写的 "r" 做前缀)。

这个限定符的值大小写不敏感。 r(表示region) 前缀用来区分地区。你不能单独指定地区。

如果用户改变了设备中语言的设定,你的App也会自动使用相应的语言。

布局方向(Layout Direction) ldrtl
ldltr

应用中 layout 的布局方向。ldrtl 表示 "从右到左布局",ldltr 表示 "从左到右布局"。 默认的值为 ldltr 。

这个设定适用于任何像layouts、drawables、values之类资源。

举个例子:如果你想为阿拉伯语提供指定的 layout 并且为其他"从右到左"的语言(如波斯语和希伯来语)提供一些一般的 layout ,那么可以这样做:

res/
    layout/   
        main.xml  (默认的layout)
    layout-ar/  
        main.xml  (为阿拉伯语定制的layout)
    layout-ldrtl/  
        main.xml  (为除了阿拉伯语外的"从右到左"的语言定制的
                   layout,
                   因为"ar"限定符的优先级更高)

记住: 如果要使用"从右到左"的布局特性,你必须设置 supportsRtl 为 "true" 并 设置 targetSdkVersion 为17或更高。

最小宽度(smallestWidth) sw<N>dp

例如:
sw320dp
sw600dp
sw720dp
等.

屏幕的最小尺寸。 其实最小宽度(smallestWidth)指的是屏幕的最小宽度和高度(你可能理解为了只是最小的宽度)。 你可以通过设定这个限定符来确保不论是横屏还是竖屏,App内的UI总是有至少<N> dps的宽度。

举个例子,如果你的layout要求屏幕的最小尺寸至少是600dp,那你可以这样来设置最小宽度(smallestWidth): res/layout-sw600dp/。这样系统只会在屏幕的最小尺寸(无论是宽度还是高度)不小于600dp时才会使用这个layout。最小宽度(smallestWidth) 是一个固定值,不会随着屏幕方向的改变而改变。

最小宽度(smallestWidth)值考虑到屏幕的布局和用户界面。 例如:如果有一些固定的UI元素占用了最小宽度中轴线的空间, 系统会把最小宽度声明的比真实的最小宽度更小,因为那些被使用了的像素你的UI已经不能使用了。 所以, 你所使用的值应该是你的layout所需要的最小尺寸(通常,这个值是你的layout所支持的最小尺寸,不论是横屏还是竖屏)。ps:这一段翻译的可能不大准确,我把官方原文的链接粘在这里这是链接。。,英语好的朋友可以直接看官方的文档。

下面列出了一些比较普遍的屏幕分辨率值,可以帮助你估量屏幕大小:

  • 320,针对那些屏幕像素如下的设备:
    • 240x320 ldpi (QVGA 手持设备)
    • 320x480 mdpi (手持设备)
    • 480x800 hdpi (高像素密度的手持设备)
  • 480,针对那些屏幕像素为 480x800 mdpi 的设备(平板/手持设备)。
  • 600,针对那些屏幕像素为 600x1024 mdpi 的设备(7" 平板)。
  • 720,针对那些屏幕像素为 720x1280 mdpi 的设备 (10" 平板)。

当你针对不同的最小宽度(smallestWidth)提供了不同的资源目录时,系统会自动使用最小宽度最接近(不超过)设备实际最小宽度的那一个目录。

这个限定符从 API level 13 开始才可使用.

可以看看 android:requiresSmallestWidthDp 属性,这个属性定义了你的App能兼容的最小宽度(smallestWidth) ,还有 smallestScreenWidthDp 属性,该属性保存了设备的最小宽度值。

可获取的宽度(Available width) w<N>dp

例如:
w720dp
w1024dp
等.

指定可获得的最小屏幕宽度,以dp为单位。这个值将会随着屏幕方向(横屏或竖屏)的改变而改变以匹配当前的实际宽度。

当你为App提供了多个资源目录,而且他们都设定了不同的可获取宽度限定符时,系统会自动选择可获取宽度最接近(不超过)当前屏幕宽度的那个。这个值会考虑到屏幕的方向,所以如果有一些固定的UI元素在屏幕的左边或右边,那么将会使用比真实屏幕大小更小的值,要注意这些UI元素并减小屏幕的可获取空间。

这个限定符从 API level 13 开始才可使用.

可以参考一下 screenWidthDp 属性,这个属性保存了当前的屏幕宽度。

可获取高度(Available height) h<N>dp

例如:
h720dp
h1024dp
等.

指定可获得的最小屏幕高度,以dp为单位。这个值将会随着屏幕方向(横屏或竖屏)的改变而改变以匹配当前的实际高度。

当你为App提供了多个资源目录,而且他们都设定了不同的可获取高度限定符时,系统会自动选择可获取高度最接近(不超过)当前屏幕高度的那个。这个值会考虑到屏幕的方向,所以如果有一些固定的UI元素在屏幕的顶部或底部,那么将会使用比真实屏幕大小更小的值,要注意这些UI元素并减小屏幕的可获取空间。

这个限定符从 API level 13 开始才可使用.

可以看看 screenHeightDp 属性, 这个属性保存了当前的屏幕高度。

屏幕大小(Screen size) small
normal
large
xlarge
  • small: 低像素密度的QVGA 屏。 一个small屏幕的最小layout大小约为 320x426 dp。例如低像素密度的QVGA和高像素密度的VGA。
  • normal: 中的像素密度的HVGA屏。一个normal屏幕的最小layout大小约为 320x470 dp 。例如低像素密度的 WQVGA屏 ,中等像素密度的HVGA屏,高像素密度的WVGA屏。
  • large: 中等像素密度的VGA屏。一个large屏幕的最小layout大小约为 480x640 dp。 例如中等像素密度的VGA和WVGA屏。
  • xlarge: 比一般的中等像素密度的HVGA屏更大的屏幕。一个xlarge屏幕的最小layout大小约为 720x960。这么大的屏幕是装不进口袋的,通常这么的大的设备是平板电脑类的设备。(xlarge这个限定符从 API level 9 开始才可使用.)

记住: 使用了大小限定符并不意味着资源只能被这个规格的屏幕使用。如果你没有为当前的屏幕配置提供更匹配的大小限定符,系统会自行使用现有资源中最匹配的那个资源。

注意: 如果你为资源目录添加了一个大于当前屏幕规格的屏幕大小限定符,系统将不会使用这些资源而且程序会在运行时崩溃!

这个限定符从 API level 4 开始才可使用.

可以看看 screenLayout 属性,这个属性反应了当前屏幕的大小是small、normal 还是 large。 

屏幕样貌(Screen aspect) long
notlong
  • long: 长屏幕,,比如:WQVGA,WVGA,FWVGA
  • notlong: 非长屏幕,比如: QVGA,HVGA,VGA

这个限定符从 API level 4 开始才可使用.

屏幕的长短是基于屏幕的长宽比决定的(一个"长"屏幕也很宽,一个"宽"的屏幕也很长),与屏幕的方向无关。

可以看看 screenLayout 属性, 这个属性反应了屏幕是否是长屏幕。

屏幕方向(Screen orientation) port
land
  • port: 设备处在竖直状态 (vertical)
  • land: 设备处在水平状态 (horizontal)

这个配置会受到屏幕的旋转的影响。

可以看看 orientation 属性,这个属性保存的设备当前所处的朝向。

UI 模式(UI mode) car
desk
television
appliance
  • car: Device is displaying in a car dock
  • desk: Device is displaying in a desk dock
  • television: Device is displaying on a television, providing a "ten foot" experience where its UI is on a large screen that the user is far away from, primarily oriented around DPAD or other non-pointer interaction
  • appliance: Device is serving as an appliance, with no display

Added in API level 8, television added in API 13.

For information about how your app can respond when the device is inserted into or removed from a dock, read Determining and Monitoring the Docking State and Type.

This can change during the life of your application if the user places the device in a dock. You can enable or disable some of these modes using UiModeManager. See Handling Runtime Changes for information about how this affects your application during runtime.

夜间模式(Night mode) night
notnight
  • night: 夜晚
  • notnight: 白天

这个限定符从 API level 8 开始才可使用.

这个设定会随着一天中时间的变化而改变。你可以通过 UiModeManager 来开启或关闭这个设定。

屏幕像素密度 (dpi) ldpi
mdpi
hdpi
xhdpi
nodpi
tvdpi
  • ldpi: 低像素密度,大约为 120dpi。
  • mdpi: 中等像素密度(一般的HVGA屏)。大约为 160dpi。
  • hdpi: 高像素密度。 大约为240dpi。
  • xhdpi: 超高像素密度。大约为 320dpi。(这个限定符从 API level 8 开始才可使用)
  • nodpi: 这个可以用于那些你不想通过缩放来匹配设备像素密度的位图资源。
  • tvdpi: 介于 mdpi 和 hdpi 的密度。大约为 213dpi。 这个值比较适合在电视(telesions)上显示,大部分的App并不需要这么设定。mdpi 和 hdpi 对于大部分App而言已经足够用了,系统会自动将这两种密度的资源缩放到合适的大小。(这个限定符从 API level 13 开始才可使用)

ldpi、mdpi、hdpi、xhdpi是按照 3:4:6:8 的比例进行缩放的。 例如:一个ldpi 的 9x9 的位图在 mdpi 下会缩放为 12x12 的位图。一个hdpi的 18x18 的位图在 xhdpi 下会被缩放成 24x24 的位图。

如果你觉得你的图片在电视上或某些设备上显示的不够好,或者只是想要尝试一下 tvdpi 像素密度,那么可以告诉你这个缩放系数是 1.33*mdpi。例如:一个mdpi的 100px x 100px 的图片在tvdpi下会变成 133px x 133px。

记住: 使用了像素密度限定符并不意味着资源只能被这个像素密度的屏幕使用。如果你没有为当前的屏幕配置提供更匹配的像素密度限定符,系统会自行使用现有资源中最匹配的那个资源。

触摸屏类型(Touchscreen type) notouch
finger
  • notouch: 设备不支持触屏。
  • finger: 设备支持触屏,可以对用户手指的触碰做出响应。

可以看看 touchscreen 属性,这个属性保存了设备屏幕的类型。

键盘可用性(Keyboard availability) keysexposed
keyshidden
keyssoft
  • keysexposed: 设备含有可用键盘。如果设备有一个能用的软键盘,那么不管用户是否外接一个硬键盘都可以使用这个软键盘。 如果没有软键盘或者软键盘不可用,那么只有外接了硬键盘时才可以使用键盘。
  • keyshidden: 设备含有可用的键盘但是键盘当前是隐藏的而且设备也没有一个可用的软键盘。
  • keyssoft: 设备含有软键盘,无论其是否可见。

如果你提供了 keysexposed 资源,但是没有提供 keyssoft 资源,系统将使用 keysexposed 资源而忽略键盘是否可见,就像系统有一个可以使用的软键盘一样。

这个设定会随着用户连接或拔下外接键盘而改变。

可以看看 hardKeyboardHidden 和 keyboardHidden 属性,他们分别保存了硬键盘的可见性和任何键盘的可见性(包括软键盘)。

第一文本输入方式(Primary text input method) nokeys
qwerty
12key
  • nokeys: 设备不含硬体键盘。
  • qwerty: 设备含有qwerty键盘, 无论其是否可见。
  • 12key: 设备含有12键(12-key)键盘,无论其是否可见。

可以看看 keyboard 属性, 这个属性反应了当前的第一文本输入方式。

API 版本(API level) 例如:
v3
v4
v7
等.

设备支持的API 版本。例如: v1表示 API level 1 (Android系统版本不低于1.0的设备), v4 表示 API level 4 (Android系统版本不低于1.6的设备)。

注意:并不是所有版本的Android都支持所有的限定符,最好总是为默认目录准备一套资源库!!!!




关于限定符的使用,要遵循以下规则:

(1) 可以通过减号(-)来同时使用多个限定符

(2) 如果同时使用多个限定符,必须按照上面这张表中各限定符出现的顺序来排列他们。

     例如:正确的排列-> drawable-hdpi-port/

                错误的排列-> drawable-port-hdpi/

(3) 资源目录不能嵌套,例如这样创建目录就是错误的:res/drawable/drawable-en/

(4) 限定符的值大小写不敏感。

(5) 每个目录同时只能支持一种类型的一个值。例如:你不能给单独一个资源目录同时添加法语和西班牙语的限定符,因为这两种限定符都是语言类的限定符。


只要你使用了相应的限定符来指定所针对的设备配置,那么系统会在加载资源时自动选择最适合当前设备的资源文件。




如何为设备提供兼容性更佳的资源:

为了能让我们的App支持更多的设备,我们最好总是为我们的App提供默认的资源目录!

举个例子吧:如果你的资源全部都设定了某种语言限定符,而且没有默认目录,那么如果设备上设置的语言中并没有对你所限定的语言的支持,那么你的App在运行时就会崩溃。但是如果你提供了一个默认目录,那么App可以正常运行,但是可能你的用户看不懂上面的文字,不过这总比直接崩溃要强。




如果转载请注明出处:http://blog.csdn.net/gophers/article/details/21281135


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值