Строковый ресурс предоставляет текстовые строки для вашего приложения с дополнительным стилем и форматированием текста. Существует три типа ресурсов, которые могут предоставить вашему приложению строки:
- Нить
- XML-ресурс, предоставляющий одну строку.
- Строковый массив
- XML-ресурс, предоставляющий массив строк.
- Количественные строки (множественное число)
- Ресурс XML, содержащий разные строки для множественного числа.
Ко всем строкам можно применять некоторую разметку стиля и аргументы форматирования. Информацию о стилях и форматировании строк см. в разделе « Форматирование и оформление» .
Нить
Одна строка, на которую можно ссылаться из приложения или из других файлов ресурсов (например, макета XML).
Примечание. Строка — это простой ресурс, ссылка на который осуществляется с использованием значения, указанного в атрибуте name
(а не имени XML-файла). Таким образом, вы можете комбинировать строковые ресурсы с другими простыми ресурсами в одном XML-файле под одним элементом <resources>
.
- расположение файла:
-
res/values/ filename .xml
Имя файла произвольное.name
элемента<string>
используется в качестве идентификатора ресурса. - тип данных скомпилированного ресурса:
- Указатель ресурса на
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>
- элементы:
- пример:
- XML-файл, сохраненный в
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Этот XML-макет применяет строку к представлению:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
Этот код приложения получает строку:
Вы можете использовать
getString(int)
илиgetText(int)
для получения строки.getText(int)
сохраняет любые стили форматированного текста, примененные к строке.
Строковый массив
Массив строк, на которые можно ссылаться из приложения.
Примечание. Массив строк — это простой ресурс, ссылка на который осуществляется с помощью значения, указанного в атрибуте name
(а не имени XML-файла). Таким образом, вы можете комбинировать ресурсы массива строк с другими простыми ресурсами в одном XML-файле в одном элементе <resources>
.
- расположение файла:
-
res/values/ filename .xml
Имя файла произвольное.name
элемента<string-array>
используется в качестве идентификатора ресурса. - тип данных скомпилированного ресурса:
- Указатель ресурса на массив
String
s. - ссылка на ресурс:
- В Java:
R.array. string_array_name
В XML:@[ package :]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>
- элементы:
- пример:
- 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>
Этот код приложения извлекает массив строк:
Котлин
val array: Array<String> =
resources
.getStringArray
(R.array.planets_array)Ява
Resources res =
getResources()
; String[] planets = res.getStringArray
(R.array.planets_array);
Количественные строки (множественное число)
В разных языках действуют разные правила грамматического согласования количества. В английском языке, например, количество 1 является особым случаем. Пишем «1 книга», но для любого другого количества будем писать « n книг». Это различие между единственным и множественным числом очень распространено, но в других языках существуют более тонкие различия. Полный набор, поддерживаемый Android: zero
, one
, two
, few
, many
и other
.
Правила принятия решения о том, какой регистр использовать для данного языка и количества, могут быть очень сложными, поэтому Android предоставляет вам такие методы, как getQuantityString()
для выбора подходящего ресурса.
Хотя исторически они называются «количественными строками» (и до сих пор называются так в API), количественные строки следует использовать только для множественного числа. Было бы ошибкой использовать строки количества для реализации чего-то вроде «Входящие» Gmail вместо «Входящие (12)», например, когда есть непрочитанные сообщения. Может показаться удобным использовать количественные строки вместо оператора if
, но важно отметить, что некоторые языки (например, китайский) вообще не делают этих грамматических различий, поэтому вы всегда получите other
строку.
Выбор используемой строки осуществляется исключительно на основе грамматической необходимости . В английском языке строка для zero
игнорируется, даже если количество равно 0, поскольку 0 грамматически не отличается от 2 или любого другого числа, кроме 1 («ноль книг», «одна книга», «две книги» и т. д.). на). И наоборот, в корейском языке всегда используется только other
строка.
Не вводите в заблуждение тот факт, что, скажем, two
звука, подобные этому, могут относиться только к числу 2: язык может требовать, чтобы 2, 12, 102 (и т. д.) рассматривались как друг друга, но по-разному по отношению к другим. количества. Положитесь на своего переводчика, чтобы узнать, на каких различиях на самом деле настаивает их язык.
Если ваше сообщение не содержит номера количества, вероятно, оно не является хорошим кандидатом на множественное число. Например, в литовском языке форма единственного числа используется и для 1, и для 101, поэтому «1 книга» переводится как «1 книга», а «101 книга» переводится как «101 книга». Между тем «книга» — это «кныга», а «много книг» — это «дауг книгу». Если английское сообщение во множественном числе содержит слова «книга» (единственное число) и «много книг» (множественное число) без фактического числа, его можно перевести как «knyga» (книга)/»daug knygų» (много книг), но с По литовским правилам будет отображаться «кныга» (одна книга), когда число будет 101.
Часто можно избежать строк количества, используя нейтральные по количеству формулировки, такие как «Книги: 1». Это облегчит вашу жизнь и жизнь ваших переводчиков, если такой стиль приемлем для вашего приложения.
В API 24+ вместо этого вы можете использовать гораздо более мощный класс ICU MessageFormat
.
Примечание. Коллекция множественного числа — это простой ресурс, ссылка на который осуществляется с использованием значения, указанного в атрибуте name
(а не имени XML-файла). Таким образом, вы можете комбинировать ресурсы множественного числа с другими простыми ресурсами в одном XML-файле под одним элементом <resources>
.
- расположение файла:
-
res/values/ filename .xml
Имя файла произвольное.name
элемента<plurals>
используется в качестве идентификатора ресурса. - ссылка на ресурс:
- На 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>
- элементы:
- пример:
- XML-файл, сохраненный в
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <!-- As a developer, you should always supply "one" and "other" strings. Your translators will know which strings are actually needed for their language. Always include %d in "one" because translators will need to use %d for languages where "one" doesn't mean 1 (as explained above). --> <item quantity="one">%d song found.</item> <item quantity="other">%d songs found.</item> </plurals> </resources>
XML-файл, сохраненный в
res/values-pl/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <item quantity="one">Znaleziono %d piosenkę.</item> <item quantity="few">Znaleziono %d piosenki.</item> <item quantity="other">Znaleziono %d piosenek.</item> </plurals> </resources>
Использование:
Котлин
val count = getNumberOfSongsAvailable() val songsFound = resources.
getQuantityString
(R.plurals.numberOfSongsAvailable, count, count)Ява
int count = getNumberOfSongsAvailable(); Resources res =
getResources()
; String songsFound = res.getQuantityString
(R.plurals.numberOfSongsAvailable, count, count);При использовании метода
getQuantityString()
вам необходимо передатьcount
дважды, если ваша строка содержит форматирование строки с числом. Например, для%d songs found
первый параметрcount
выбирает соответствующую строку во множественном числе, а второй параметрcount
вставляется в заполнитель%d
. Если ваши строки во множественном числе не включают форматирование строк, вам не нужно передавать третий параметр вgetQuantityString
.
Формат и стиль
Вот несколько важных вещей, которые вам следует знать о том, как правильно форматировать и стилизовать строковые ресурсы.
Обработка специальных символов
Если строка содержит символы, которые имеют специальное использование в XML, вы должны экранировать символы в соответствии со стандартными правилами экранирования XML/HTML. Если вам нужно экранировать символ, имеющий особое значение в Android, вам следует использовать обратную косую черту перед ним.
По умолчанию Android сжимает последовательности пробельных символов в один пробел. Вы можете избежать этого, заключив соответствующую часть строки в двойные кавычки. В этом случае все пробелы (включая новые строки) сохранятся в пределах кавычек. Двойные кавычки также позволят вам использовать обычные одинарные неэкранированные кавычки.
Характер | Сбежавшие формы |
---|---|
@ | \@ |
? | \? |
Новая линия | \n |
Вкладка | \t |
U+XXXX символ Юникода | \uXXXX |
Одинарная кавычка ( ' ) | Любое из следующего:
|
Двойная кавычка ( " ) | \" Обратите внимание, что заключение строки в одинарные кавычки не работает. |
Свертывание пробелов и экранирование Android происходит после того, как ваш файл ресурсов анализируется как XML. Это означает, что <string>      </string>
(пробел, пробел для знаков препинания, пробел для Unicode Em) все сворачиваются в один пробел ( " "
), поскольку все они представляют собой пробелы в Юникоде после анализа файла как XML. Чтобы сохранить эти пробелы такими, какие они есть, вы можете либо заключить их в кавычки ( <string>"      "</string>
), либо использовать экранирование Android ( <string> \u0032 \u8200 \u8195</string>
>).
Примечание. С точки зрения анализатора XML нет никакой разницы между <string>"Test this"</string>
и <string>"Test this"</string>
. Обе формы не будут отображать кавычки, но активируют кавычки Android с сохранением пробелов (в данном случае это не будет иметь практического эффекта).
Форматирование строк
Если вам нужно отформатировать строки, вы можете сделать это, поместив аргументы формата в строковый ресурс, как показано в следующем примере ресурса.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
В этом примере строка формата имеет два аргумента: %1$s
— это строка, а %2$d
— десятичное число. Затем отформатируйте строку, вызвав getString(int, Object...)
. Например:
Котлин
var text = getString(R.string.welcome_messages, username, mailCount)
Ява
String text = 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>, <cite>, <dfn>, <em>
- Увеличение текста на 25 %: <big>
- Текст на 20% меньше: <small>
- Установка свойств шрифта: <font face="font_family" color="hex_color">. Примеры возможных семейств шрифтов включают
monospace
,serif
иsans_serif
. - Установка семейства моноширинных шрифтов: <tt>
- Зачеркивание: <s>, <strike>, <del>
- Подчеркнуть: <u>
- Надстрочный индекс: <sup>
- Индекс: <sub>
- Точки списка: <ul>, <li>
- Разрывы строк: <br>
- Подразделение: <div>
- Стиль CSS: <span style="color|background_color|text-decoration">
- Параграфы: <p dir="rtl | ltr» style="…">
Если вы не применяете форматирование, вы можете установить текст TextView напрямую, вызвав setText(java.lang.CharSequence)
. Однако в некоторых случаях может потребоваться создать стилизованный текстовый ресурс, который также будет использоваться в качестве строки формата. Обычно это не работает, поскольку методы format(String, Object...)
и getString(int, Object...)
удаляют всю информацию о стиле из строки. Обходной путь заключается в написании HTML-тегов с экранированными сущностями, которые затем восстанавливаются с помощью fromHtml(String)
после форматирования. Например:
- Сохраните свой стилизованный текстовый ресурс как строку с экранированием HTML:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
В эту форматированную строку добавляется элемент
<b>
. Обратите внимание, что открывающая скобка экранируется HTML с помощью<
обозначения. - Затем отформатируйте строку как обычно, а также вызовите
fromHtml(String)
для преобразования текста HTML в стилизованный текст:Котлин
val text: String = getString(R.string.welcome_messages, username, mailCount) val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)
Ява
String text = getString(R.string.welcome_messages, username, mailCount); Spanned styledText = Html.fromHtml(text, FROM_HTML_MODE_LEGACY);
Поскольку метод fromHtml(String)
форматирует все объекты HTML, обязательно экранируйте любые возможные символы HTML в строках, которые вы используете с форматированным текстом, с помощью htmlEncode(String)
. Например, если вы форматируете строку, содержащую такие символы, как «<» или «&», перед форматированием их необходимо экранировать, чтобы при прохождении форматированной строки через fromHtml(String)
символы выходили в нужном направлении. они были написаны изначально. Например:
Котлин
val escapedUsername: String = TextUtils.htmlEncode
(username)
val text: String = getString(R.string.welcome_messages, escapedUsername, mailCount)
val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)
Ява
String escapedUsername = TextUtils.htmlEncode
(username);
String text = getString(R.string.welcome_messages, escapedUsername, mailCount);
Spanned styledText = Html.fromHtml(text);
Стилизация с помощью Spanables
Spannable
— это текстовый объект, который можно стилизовать с помощью свойств шрифта, таких как цвет и насыщенность шрифта. Вы используете SpannableStringBuilder
для создания текста, а затем применяете к тексту стили, определенные в пакете android.text.style
.
Вы можете использовать следующие вспомогательные методы для выполнения большей части работы по созданию составного текста:
Котлин
/** * 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 fun apply(content: Array<out CharSequence>, vararg tags: Any): CharSequence { return SpannableStringBuilder().apply { openTags(tags) content.forEach { charSequence -> append(charSequence) } closeTags(tags) } } /** * 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 fun Spannable.openTags(tags: Array<out Any>) { tags.forEach { tag -> 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 fun Spannable.closeTags(tags: Array<out Any>) { tags.forEach { tag -> if (length > 0) { setSpan(tag, 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE) } else { removeSpan(tag) } } }
Ява
/** * 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 applyStyles(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. */ fun bold(vararg content: CharSequence): CharSequence = apply(content, StyleSpan(Typeface.BOLD)) /** * Returns a CharSequence that applies italics to the concatenation * of the specified CharSequence objects. */ fun italic(vararg content: CharSequence): CharSequence = apply(content, StyleSpan(Typeface.ITALIC)) /** * Returns a CharSequence that applies a foreground color to the * concatenation of the specified CharSequence objects. */ fun color(color: Int, vararg content: CharSequence): CharSequence = apply(content, ForegroundColorSpan(color))
Ява
/** * 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. val text: CharSequence = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world)))
Ява
// Create an italic "hello, " a red "world", // and bold the entire sequence. CharSequence text = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world)));
Kotlin-модуль core-ktx также содержит функции расширения, которые еще больше упрощают работу с интервалами. Чтобы узнать больше, вы можете ознакомиться с документацией по пакету android.text на GitHub.
Дополнительную информацию о работе с интервалами см. по следующим ссылкам:
Стилизация с аннотациями
Вы можете применить сложный или собственный стиль, используя класс Annotation
вместе с тегом <annotation>
в файлах ресурсов strings.xml. Тег аннотации позволяет помечать части строки для пользовательского стиля, определяя пользовательские пары ключ-значение в XML, которые платформа затем преобразует в диапазоны Annotation
. Затем вы можете получить эти аннотации и использовать ключ и значение для применения стиля.
При создании аннотаций обязательно добавляйте тег <annotation>
ко всем переводам строки в каждом файле strings.xml.
Применение собственного шрифта к слову «текст» на всех языках
Пример — добавление собственного шрифта
Добавьте тег
<annotation>
и определите пару ключ-значение. В данном случае ключом является шрифт , а значением — тип шрифта, который мы хотим использовать: title_emphasis.// values/strings.xml <string name="title">Best practices for <annotation font="title_emphasis">text</annotation> on Android</string> // values-es/strings.xml <string name="title"><annotation font="title_emphasis">Texto</annotation> en Android: mejores prácticas</string>
Загрузите строковый ресурс и найдите аннотации с помощью ключа шрифта . Затем создайте собственный диапазон и замените существующий диапазон.
Котлин
// get the text as SpannedString so we can get the spans attached to the text val titleText = getText(R.string.title) as SpannedString // get all the annotation spans from the text val annotations = titleText.getSpans(0, titleText.length, Annotation::class.java) // create a copy of the title text as a SpannableString. // the constructor copies both the text and the spans. so we can add and remove spans val spannableString = SpannableString(titleText) // iterate through all the annotation spans for (annotation in annotations) { // look for the span with the key font if (annotation.key == "font") { val fontName = annotation.value // check the value associated to the annotation key if (fontName == "title_emphasis") { // create the typeface val typeface = getFontCompat(R.font.permanent_marker) // set the span at the same indices as the annotation spannableString.setSpan(CustomTypefaceSpan(typeface), titleText.getSpanStart(annotation), titleText.getSpanEnd(annotation), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) } } } // now, the spannableString contains both the annotation spans and the CustomTypefaceSpan styledText.text = spannableString
Ява
// get the text as SpannedString so we can get the spans attached to the text SpannedString titleText = (SpannedString) getText(R.string.title); // get all the annotation spans from the text Annotation[] annotations = titleText.getSpans(0, titleText.length(), Annotation.class); // create a copy of the title text as a SpannableString. // the constructor copies both the text and the spans. so we can add and remove spans SpannableString spannableString = new SpannableString(titleText); // iterate through all the annotation spans for (Annotation annotation: annotations) { // look for the span with the key font if (annotation.getKey().equals("font")) { String fontName = annotation.getValue(); // check the value associated to the annotation key if (fontName.equals("title_emphasis")) { // create the typeface Typeface typeface = ResourcesCompat.getFont(this, R.font.roboto_mono); // set the span at the same indices as the annotation spannableString.setSpan(new CustomTypefaceSpan(typeface), titleText.getSpanStart(annotation), titleText.getSpanEnd(annotation), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } } // now, the spannableString contains both the annotation spans and the CustomTypefaceSpan styledText.text = spannableString;
Если вы используете один и тот же текст несколько раз, вам следует создать объект SpannableString один раз и повторно использовать его по мере необходимости, чтобы избежать потенциальных проблем с производительностью и памятью.
Дополнительные примеры использования аннотаций см. в разделе «Стилизация интернационализированного текста в Android».
Промежутки аннотаций и разделение текста
Поскольку диапазоны Annotation
также являются ParcelableSpans
, пары ключ-значение являются пакетированными и непакетируемыми. Если получатель пакета знает, как интерпретировать аннотации, вы можете использовать диапазоны Annotation
, чтобы применить собственный стиль к фрагментированному тексту.
Чтобы сохранить собственный стиль при передаче текста в Intent Bundle, сначала необходимо добавить к тексту диапазоны Annotation
. Вы можете сделать это в ресурсах XML с помощью тега <annotation>, как показано в примере выше, или в коде, создав новую Annotation
и установив ее как диапазон, как показано ниже:
Котлин
val spannableString = SpannableString("My spantastic text") val annotation = Annotation("font", "title_emphasis") spannableString.setSpan(annotation, 3, 7, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) // start Activity with text with spans val intent = Intent(this, MainActivity::class.java) intent.putExtra(TEXT_EXTRA, spannableString) startActivity(intent)
Ява
SpannableString spannableString = new SpannableString("My spantastic text"); Annotation annotation = new Annotation("font", "title_emphasis"); spannableString.setSpan(annotation, 3, 7, 33); // start Activity with text with spans Intent intent = new Intent(this, MainActivity.class); intent.putExtra(TEXT_EXTRA, spannableString); this.startActivity(intent);
Получите текст из Bundle
как SpannableString
, а затем проанализируйте прикрепленные аннотации, как показано в примере выше.
Котлин
// read text with Spans val intentCharSequence = intent.getCharSequenceExtra(TEXT_EXTRA) as SpannableString
Ява
// read text with Spans SpannableString intentCharSequence = (SpannableString)intent.getCharSequenceExtra(TEXT_EXTRA);
Дополнительную информацию о стилизации текста можно найти по следующим ссылкам: