第九章 多语言环境的支持和多屏幕的适配(1)

第九章 多语言环境的支持和多屏幕的适配

资源是在代码中使用到的,并且在编译时被打包进应用程序的附加文件。出于加载效率的考虑,资源被从代码中分离出来,而且XML文件被编译进二进制代码中。在Android中,程序代码可以不直接和资源发生关系,而是通过R文件提供的索引来间接的引用某一个资源。Android系统会自动根据用户当前的环境,和屏幕分辨率情况,自动选用最合适的资源。正是基于Android系统这种独特的处理方式,开发者可以编写多套资源文件,从而很方便的实现多语言环境的支持和多种屏幕的适配。

本章将详细说明Android程序的资源的结构,以及具体如何适配多语言环境和多种屏幕。

9.1Android程序的资源文件

9.1.1资源文件的目录结构

资源是外部文件(即非代码文件),它在代码中被使用,是在编译的时候加载到应用程序的。Android支持很多种不同类型的资源文件,包括XMLPNGJPEG等文件。在Eclipse的工程中,res目录有默认几项resource,比如:

1res/drawable/---图像类型的资源文件。

2res/layout/---可被编译成屏幕布局(部分布局)的XML文件。

3res/values/---可被编译成多种类型的资源的XML文件。文件可以被命名为任何名字,这个文件夹有一些经典的文件(一般约定以文件中定义的元素名称来给文件命名):

  • arrays.xml定义数组。

  • colors.xml定义颜色和颜色字符串值。分别用Resources.getDrawable()Resources.getColor()方法获取这些资源。

  • dimens.xml定义尺寸数据,可以用Resources.getDimension()方法取得这些资源。

  • strings.xml定义字符串值,可以用Resources.getString()或者Resources.getText()方法来获取这些资源。其中getText()方法将保留任何丰富的通常在UI中描述的文字样式。)

  • styles.xml定义样式对象。

4res/menu/---菜单对象的XML文件,可以通过重载Activity类的onCreateOptionsMenu()方法,使用“MenuInflaterinflater = getMenuInflater(); inflater.inflateR.menu.menu,menu; ”代码片段来获取。

5res/anim/---XML文件,被编译成逐帧动画或者是补间动画的对象。

6res/xml/---用来放置stylethemexml文件的定义。也可放置任何XML文件,在运行时可通过Resources.getXML()方法读取。

7res/raw/---存放任何被直接拷贝到设备上的文件。在程序被编译时,它们直接加到压缩文件中。在应用程序中可以通过用Resources.openRawResource(id)方法来获取资源,id的形式为:R.raw.filename

所有资源都会被编译到最终的APK文件里。Android会自动创建一个类——R.java,这样你在代码中可以通过它关联到对应的资源文件。R.java中包含的子类的命名由资源的路径和文件的名称决定。


经验分享:

上述res/values/目录下的文件命名(arrays.xmlcolors.xml等等)只是Android官方推荐的名称。实际上,无论文件如何命名,比如命名为my.xml,也都是可以的。

另外,如果项目工程较大,包含很多的模块,就可以考虑以模块化的方式配置资源文件。比如整个项目用到的字符串,可以根据模块划分,命名为“模块1简称_strings.xml”、“模块2简称_strings.xml”等等,这样方便以后的维护。

9.1.2 资源文件目录的修饰语

Android通过检测硬件和语言的设置,去加载特定的资源文件。用户可以在系统的设置中设置系统的语言。为了包含各种替代资源,需要在同一目录下创建并行的文件夹,并且在每个文件夹名字后面加上相应的指定,说明它使用的配置(如语言,屏幕的方向等等)。例如,下面是一个工程中包含一个字符串资源,一个是英文版的,一个是法文版的:

res/

---->values-en/

--------------->strings.xml

----->values-fr/

--------------->strings.xml


Android检测到系统语言为英文的时候,就会自动去查找资源文件中最符合的资源来给代码调用,这里将会调用values-en/strings.xml,而当系统语言为法文的时候,则会调用values-fr/strings.xml

既然存在多种替代资源,这里就会有Android加载资源文件的步骤的问题。所有的资源文件名都可以加上一个或多个修饰语,在调用资源的时候,系统通过检测硬件和语言的设置一层一层的筛选,找出最匹配的资源返回。Android系统支持很多种不同类型的修饰语,把修饰语加在资源文件夹名字的后面,通过破折号隔开。并可以将多个修饰语加在文件夹的后面,但是它们必须按照规定的顺序出现。例如,一个文件夹包含图像资源,并且完全指定出所有配置,如下所示:

res/drawable-en-rUS-port-160dpi-finger-keysexposed-qwerty-dpad-480x320/


当然,你可以只指定一部分配置项,而将其他修饰语删除掉,只要将剩下的修饰语保留正确的顺序就可以。

下面我们按照顺序来对这些修饰语进行详细说明,请参考表9-1

修饰语

语言

两个小写字母参照ISO639-1 标准。例如:enfres

地区

一个小写字母加两个大写字母,参照ISO3166-1-alpha-2 标准。

例如:rUSrFRrES

屏幕方向

Port(竖屏),land(横屏),square

屏幕像素

92dpi108dpi,等等

触摸屏类型

Notouch(不支持触屏),stylus(手写笔),finger(手指触摸)

键盘是否可用

Keysexposed(可用),keyshidden(不可用)

文本输入模式

Nokeys(无键盘),qwerty(标准传统键盘),12key12个键)

导航模式

Nonavdpadtrackballwheel

屏幕分辨率

320×240800×480,等等。大分辨率需要开始声明。

9-1资源文件目录的修饰语


上面的这个列表,不包含设备的特殊参数,如载体、商标、设备/硬件、制造商。任何应用程序需要知道的设备信息,都在上面表格中的资源修饰语里。

下面是一些通用的关于资源目录的命名规范:

  • 各个变量用破折号分开(每个基本的目录名后跟一个破折号)

  • 变量是区分大小写的(所有变量名的大小写必须保持一致)

例如,一个drawable的目录必须命名为drawable-port,而不是drawable-PORT

  • 你不能有两个目录命名为drawable-portdrawable-PORT,即使故意将“port”和“PORT”指向不同的参数值。

  • 同一类型的修饰语在一个文件名中只能出现一次(你不能这样命名drawable-rENrFR

  • 你可以指定多个参数来定义具体的配置,但参数必须保持上面表格中的顺序。例如,drawable-en-rUS-land指在US-English的设备上使用。

  • Android会试图找到最适合当前配置的目录,关于这一点将在下面详细讲述

  • 表格里所有的参数的顺序是用来防止多个合格目录的事件发生(可看下面的例子)

  • 所有的目录,无论是否合格,都是放在res/目录下的。合格的目录是不能嵌套的(你不能这样写res/drawable/drawable-en

  • 所有的资源将在代码或简单的资源引用语法,不加修饰的名字。因此,如果一个资源被命名为:

res/drawable-port-92dp/myimage.png

那么它可以这样被引用:

R.drawable.myimage(在代码中)

@drawable/myimage(在XML文件中)

9.1.3 程序加载资源文件的步骤

既然有如此繁多的资源文件,那么我们如何来对他们进行分类,并且做到国际化和本地化呢?这里,我们就必须先了解Android加载资源文件的步骤。

Android将挑选哪些资源文件在运行时会被使用,这取决于当前的配置。选择过程如下:

1)先找出包含匹配的资源的所有文件夹。

比如我们用到了资源myimage.png,而有下面的四个文件夹都包含这个资源。

res/drawable/myimage.png

res/drawable-en/myimage.png

res/drawable-port/myimage.png

res/drawable-port-92dpi/myimage.png


2)然后清除所有的不符合当前设备配置的资源。

例如,如果当前屏幕的像素是108dpi,那么将清除res/drawable-port-92dpi/。剩余下面的目录。

res/drawable/myimage.png

res/drawable-en/myimage.png

res/drawable-port/myimage.png


当前语言是en-GB,屏幕方向是port,那么有两个符合配置的选项:res/drawable-en/res/drawable-port/,目录res/drawable/将被清除,因为它和当前的配置有0个属性相同,而其他两个文件有一个和配置文件相同的属性。此时剩余下面的目录。

res/drawable-en/myimage.png

res/drawable-port/myimage.png


3)如果还有多个目录存在,则根据配置的优先级选取最终的资源文件。

上面表格的修饰语就是按照优先级来写的。也就是说,语言的优先级比屏幕方向的优先级高,所以在这个例子中,我们会通过语言环境来优先选择res/drawable-en/目录。最终只剩下下面的目录,系统会在此目录下选择文件。

res/drawable-en/myimage.png


9.2国际化和本地化的支持

Internationalization(国际化)简称i18n,因为在in之间还有18个字符。Localization(本地化),简称L10n。国际化和本地化有一个通用的标准,一般的,在说明一个地区的语言时,用“语言_地区”的形式,比如zh_CNzh_TW等等。

Android系统对i18nL10n提供了非常好的支持。Android没有专门的API来提供国际化,而是通过对不同resource的命名来达到国际化的目的。同时,这种命名方法还可用于对硬件的区分,比如不同的新视屏,使用不同的图片资源。

下面的章节会详细的进行说明。

比如有两个string.xml的资源文件,分别在res\values目录下和res\values-zh目录下。

res\values\string.xml

<?xmlversion="1.0" encoding="utf-8"?>

<resources>

<stringname="hello">Hello, Test!</string>

</resources>


res\values-zh\string.xml

<?xmlversion="1.0" encoding="utf-8"?>

<resources>

<stringname="hello">你好,测试</string>

</resources>


在代码中调用:

Stringhello = getResources().getStringArray(R.string.hello);


如果系统的语言是中文的情况下,hello的值是“你好,测试”;在其它情况下,hello的值是“Hello,Test!”

从以上的示例可以看到,只要简单的通过对资源目录进行适当的命名,就可以实现应用程序的国际化。


经验分享:

需要国际化的内容,一般包括所有文字信息(包括带有文字的图片)。

一般的,在实际项目中,国际化的工作是另外一个团队完成的。所以,开发人员在开发过程中,务必不要在代码中直接硬编码可能需要国际化的内容,而是将这些内容统统都写到资源文件中,在代码中通过资源的ID进行引用。这样,国际化团队只需要对部分资源文件进行国际化即可。

国际化过程还有一个难点是,国际化以后,由于不同语言的字符长度串不同,UI布局可能有所改变,这就需要国际化以后仔细的进行测试。



阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页