Android应用中的字符串资源类型(String Resources)

字符串资源给应用程序提供带有文本样式和格式选项的文本字符串。能够给应用程序提供三种类型的字符串资源:

  • String

    提供单一字符串的XML资源。

  • String Array

    提供一个字符串数组的XML资源

  • Quantity Strings(Plurals)

    同一个单词或短语在不同数量时所使用的不同字符串的XML资源文件。通常指单词或短语的单/复数形式。

所有的字符串都有使用一些样式标记和格式化参数的能力。

String

应用程序的代码中或其他资源的XML文件(如XML布局文件)中能够引用的一个单一字符串。

注意:字符串是一个简单的资源,能够使用name属性(不是XML文件的名字)的值来引用这个字符串。因此,可以把字符资源与其他类型的简单资源组合到一个XML文件的<resources>元素下。

文件位置

res/values/filename.xml
文件名是任意的,<string>元素的name属性值会被用作资源ID。

被编译资源的数据类型

资源指向一个String对象。

资源引用

  • 在Java代码中:
    R.string.string_name;
  • 在XML中:
    @string/string_name。

语法

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string
        name="string_name"
        >text_string</string>
</resources>

元素

<resources>元素

必须的。它必须是根节点。没有属性。

<string>元素

定义一个字符串,它能够包含样式标签。要注意的是,单引号和双引号必须做语义转换。

<string>元素属性

name——字符串值,它定义了字符串的名称,这个名称会被用于资源ID。

例子

XML文件被保存在res/values/strings.xml中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello!</string>
</resources>

以下布局XML会这个字符串应用到一个View对象上:

<TextView
    Android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello" />

以下是应用程序代码获取字符串资源的方法:

String string = getString(R.string.hello);

可以使用getString(int)或getText()方法来获取一个字符串。getText(int)方法会获取使用样式的字符串的富文本。

String Array

定义能够被应用程序引用的字符串数组。

注意:字符串数组是一个简单资源,使用name(不是XML文件的名字)属性中提供的值来引用。例如,能够把字符串数组资源和其他的简单资源组合到一个XML文件的<resources>元素下。

文件位置

res/values/filename.xml
文件名是任意的。<string-array>元素的name属性值被用做资源ID。

被编译资源的数据类型

资源指向一个字符串数组对象。

资源引用

  • 在Java代码中
    R.array.string_array_name

语法

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array
        name="string_array_name">
        <item
            >text_string</item>
    </string-array>
</resources>

元素

<resources>元素

必须的。它必须是根节点。没有属性。

<string-array>元素

定义一个字符串数组,它要包含一个或多个元素。

<string-array>元素属性

name——字符串值,它定义了数组的名称。这个名称被用于引用数组的资源ID。

<item>元素

定义一个能够包含样式标签的字符串,它的值可以是另一个字符串资源的应用。它必须是<string-array>元素的子元素。要注意的是,单引号和双引号必须进行转义处理。

例子

XML文件被保存在res/values/strings.xml中:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="planets_array">
        <item>Mercury</item>
        <item>Venus</item>
        <item>Earth</item>
        <item>Mars</item>
    </string-array>
</resources>

以下应用程序代码获取字符串数组的方法:

Resources res =getResources();
String[] planets = res.getStringArray(R.array.planets_array);

Quantity Strings(Plurals)

不同的语言对于数量有不同的语法规则。例如,在英语中,数量1是一种特殊的情况,被写做1 book,但是其他的数量要被写成n book。这是非常普通的单/复数之间的区分,而其他的语言会有更细的区分。Android支持的完整设置如下:zero、one、two、few、many和other。

用给定的语言和数量来判断使用哪一种规则是非常复杂的,因此Android提供了一些方法,来为应用程序选择合适的资源,如getQuantityString()方法。

要注意的是,选择是基于语言语法的必要性。在英语中对于数量设置为zero的字符串,即使是数量为0也会被忽略,因为0数量在语法上除了1以外,与其他数量没有区别(zero books、one book、two books等等)。不要被表面现象所误导,要根据实际的语言语法差异来进行区分。

通常要尽可能的使用中性的数量描述来避免语言语法的差异,如“Books:1”。如果在应用程序中保持这种风格,这将使处理语言语法上的差异变得更加容易。

注意:一个复数单词和短语的集合是一个简单的资源,使用name属性中提供的值就可以引用这个资源。例如,可以把复数单词或短语的资源与其他简单的资源一起组合到一个XML文件的<resources>元素中。

文件位置

res/values/filename.xml
文件名是任意的。<plurals>元素的name属性值将会被用作资源ID。

资源引用

  • 在Java代码中:
    R.plurals.plural_name

语法

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <plurals
        name="plural_name">
        <item
            quantity=["zero" | "one" | "two" | "few" | "many" | "other"]
            >text_string</item>
    </plurals>
</resources>

元素

<resources>元素

必须的,它必须是根节点。没有属性。

<plurals>元素

它定义了一个字符串的集合,集合提供的每一个字符串都要依赖于某些数量词。它包含了一个或多个<item>元素。

<plurals>元素属性

name——一个字符串值,它定义字符串的名称,这个名称被用作资源ID。

<item>元素

它定义了一个单数或复数场合使用的字符串。它能够引用另一个字符串资源。它必须是元素的子元素。要注意的是,单引号和双引号必要要使用转义字符。

<item>元素属性

quatity——它是一个关键词,用于指示该字符串所使用的时机。有效值如下:

说明
zero当语言中需要对数量词0进行特殊处理时,要使用这个设置(如阿拉伯语)
one当语言中需要对像1这样的数量词进行特殊处理时,要使用这个设置(如英语)
two当语言中需要对像2这样的数量词进行特殊处理时,要使用这个设置(如威尔士语)
few当语言中需要对小的数量词进行特殊处理时,要使用这个设置。(如捷克语中带有2、3和4的数量词;或是波兰语中以2、3、4结尾但不是12、13、14的数量词。)
many当语言中需要对大的数量词进行特殊处理时,要使用这个设置。(如马耳他语中以11---99之间的数字结尾的数量词。)
other当语言中不需要对给定的数量进行特殊处理时,使用这个设置。

例子

XML文件被保存在res/values/strings.xml和res/values-pl/strings.xml中:
res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <pluralsname="numberOfSongsAvailable">
        <itemquantity="one">One song found.</item>
        <itemquantity="other">%d songs found.</item>
    </plurals>
</resources>

res/values-pl/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <pluralsname="numberOfSongsAvailable">
        <itemquantity="one">Znaleziono jedną piosenkę.</item>
        <itemquantity="few">Znaleziono %d piosenki.</item>
        <itemquantity="other">Znaleziono %d piosenek.</item>
    </plurals>
</resources>

Java代码中的用法如下:

int count = getNumberOfsongsAvailable();
Resources res =getResources();
String songsFound = res.getQuantityString(R.plurals.numberOfSongsAvailable, count, count);

当使用getQuantityString()方法时,如果字符串中包含了带有数字的字符串格式,就需要传递count参数两次。例如,对于字符串“%d songs found”,第一个count参数会选择合适的复数字符串,第二个参数会插入到%d位置。如果复数字符串不包含格式化字符,就不需要传递第三个参数给getQuantityString()方法。

格式和样式设置

关于如何正确设置字符串资源的格式和样式,您应该了解下面这几个要点。

转义撇号和引号

如果字符串中包含撇号 ('),您必须用反斜杠 (\') 将其转义,或为字符串加上双引号 ("")。 例如,以下是一些有效和无效的字符串:

<string name="good_example">This\'ll work</string>
<string name="good_example_2">"This'll also work"</string>
<string name="bad_example">This doesn't work</string>
    <!-- Causes a compile error -->

如果字符串中包含双引号,您必须将其转义(使用 \")。 为字符串加上单引号不起作用。

<string name="good_example">This is a \"good string\".</string>
<string name="bad_example">This is a "bad string".</string>
    <!-- Quotes are stripped; displays as: This is a bad string. -->
<string name="bad_example_2">'This is another "bad string".'</string>
    <!-- Causes a compile error -->

设置字符串格式

如果您需要使用 String.format(String, Object...) 设置字符串格式,可以通过在字符串资源中加入格式参数来实现。 例如,对于以下资源:

<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

在本例中,格式字符串有两个参数:%1$s 是一个字符串,而 %2$d 是一个十进制数字。 您可以像下面这样使用应用中的参数设置字符串格式:

Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);

使用 HTML 标记设置样式

您可以使用 HTML 标记为字符串添加样式设置。例如:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="welcome">Welcome to <b>Android</b>!</string>
</resources>

支持的 HTML 元素包括:

  • <b> 表示粗体文本。

  • <i> 表示斜体文本。

  • <u> 表示 下划线 文本。

有时,您可能想让自己创建的带样式文本资源同时也用作格式字符串。 正常情况下,这是行不通的,因为 String.format(String, Object...) 方法会去除字符串中的所有样式信息。 这个问题的解决方法是编写带转义实体的 HTML 标记,在完成格式设置后,这些实体可通过 fromHtml(String) 恢复。 例如:

  • 将您带样式的文本资源存储为 HTML 转义字符串:
<resources>
  <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d new messages&lt;/b>.</string>
</resources>

在这个带格式的字符串中,添加了 <b> 元素。请注意,开括号使用 < 表示法进行了 HTML 转义。

  • 然后照常设置字符串格式,但还要调用 fromHtml(String) 以将 HTML 文本转换成带样式文本:
Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), username, mailCount);
CharSequence styledText = Html.fromHtml(text);

由于 fromHtml(String) 方法将设置所有 HTML 实体的格式,因此务必要使用 htmlEncode(String) 对您用于带格式文本的字符串中任何可能的 HTML 字符进行转义。 例如,如果您向 String.format() 传递的字符串参数可能包含“<”或“&”之类的字符,则必须在设置格式前进行转义,这样在通过 fromHtml(String) 传递带格式字符串时,字符就能以原始形式显示出来。 例如:

String escapedUsername = TextUtil.htmlEncode(username);

Resources res = getResources();
String text = String.format(res.getString(R.string.welcome_messages), escapedUsername, mailCount);
CharSequence styledText = Html.fromHtml(text);

使用 Spannable 设置样式

Spannable 是一种文本对象,让您可以使用颜色和字体粗细等字体属性进行样式设置。 您可以使用 SpannableStringBuilder 生成文本,然后对文本应用 android.text.style 包中定义的样式。

您可以利用下列辅助工具方法来设置许多 spannable 文本创建工作:

/**
 * Returns a CharSequence that concatenates the specified array of CharSequence
 * objects and then applies a list of zero or more tags to the entire range.
 *
 * @param content an array of character sequences to apply a style to
 * @param tags the styled span objects to apply to the content
 *        such as android.text.style.StyleSpan
 *
 */
private static CharSequence apply(CharSequence[] content, Object... tags) {
    SpannableStringBuilder text = new SpannableStringBuilder();
    openTags(text, tags);
    for (CharSequence item : content) {
        text.append(item);
    }
    closeTags(text, tags);
    return text;
}

/**
 * Iterates over an array of tags and applies them to the beginning of the specified
 * Spannable object so that future text appended to the text will have the styling
 * applied to it. Do not call this method directly.
 */
private static void openTags(Spannable text, Object[] tags) {
    for (Object tag : tags) {
        text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK);
    }
}

/**
 * "Closes" the specified tags on a Spannable by updating the spans to be
 * endpoint-exclusive so that future text appended to the end will not take
 * on the same styling. Do not call this method directly.
 */
private static void closeTags(Spannable text, Object[] tags) {
    int len = text.length();
    for (Object tag : tags) {
        if (len > 0) {
            text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
        } else {
            text.removeSpan(tag);
        }
    }
}

以下 bold、italic 和 color 方法向您展示了如何调用这些帮助程序方法来应用 android.text.style 包中定义的样式。 您可以创建类似方法来进行其他类型的文本样式设置。

/**
 * Returns a CharSequence that applies boldface to the concatenation
 * of the specified CharSequence objects.
 */
public static CharSequence bold(CharSequence... content) {
    return apply(content, new StyleSpan(Typeface.BOLD));
}

/**
 * Returns a CharSequence that applies italics to the concatenation
 * of the specified CharSequence objects.
 */
public static CharSequence italic(CharSequence... content) {
    return apply(content, new StyleSpan(Typeface.ITALIC));
}

/**
 * Returns a CharSequence that applies a foreground color to the
 * concatenation of the specified CharSequence objects.
 */
public static CharSequence color(int color, CharSequence... content) {
    return apply(content, new ForegroundColorSpan(color));
}

下面这个示例展示了如何将这些方法链接起来,创建出对不同词语应用不同类型样式的字符序列:

// Create an italic "hello, " a red "world",
// and bold the entire sequence.
CharSequence text = bold(italic(res.getString(R.string.hello)),
    color(Color.RED, res.getString(R.string.world)));
Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1