Os recursos de string fornecem strings de texto para o aplicativo com estilo e formatação de texto opcionais. Existem três tipos de recursos que podem fornecer strings ao seu aplicativo:
- String
- Recurso XML que fornece uma só string.
- Matriz de strings
- Recurso XML que fornece uma matriz de strings.
- Strings de quantidade (plurais)
- Recurso XML que contém diferentes strings para pluralização.
Todas as strings podem aplicar algumas marcações de estilo e argumentos de formatação. Para saber mais sobre estilos e formatação de strings, consulte a seção sobre Formatação e estilo.
String
É uma string única que pode ser referenciada do aplicativo ou de outros arquivos de recurso (como um layout XML).
Observação: as strings são recursos simples que são referenciados usando o valor fornecido no atributo name
(não o nome do arquivo XML). Dessa forma, é possível combinar recursos de string com outros recursos simples em um arquivo XML, em um elemento <resources>
.
- local do arquivo:
res/values/filename.xml
O atributo “filename” é arbitrário. Oname
do elemento<string>
é usado como o código do recurso.- tipo de dados do recurso compilado:
- Ponteiro do recurso para um
String
. - referência do recurso:
-
Em Java:
R.string.string_name
Em XML:@string/string_name
- sintaxe:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- elementos:
- exemplo:
- Arquivo XML salvo em
res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Esse XML de layout aplica uma string em uma Visualização:
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />
Esse código de aplicativo recupera uma string:
Você pode usar
getString(int)
ougetText(int)
para recuperar uma string.getText(int)
manterá qualquer estilo de texto avançado aplicado à string.
Matriz de strings
É a matriz de strings que pode ser referenciada pelo aplicativo.
Observação: a matriz de strings é um recurso simples referenciado usando o valor fornecido no atributo name
(não o nome do arquivo XML). Dessa forma, você pode combinar recursos da matriz da string com outros recursos simples em um arquivo XML, em um elemento <resources>
.
- local do arquivo:
res/values/filename.xml
O atributo “filename” é arbitrário. Oname
do elemento<string-array>
é usado como o código do recurso.- tipo de dados do recurso compilado:
- Ponteiro de recurso para uma matriz de
String
s. - referência do recurso:
-
Em Java:
R.array.string_array_name
- sintaxe:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- elementos:
- exemplo:
- Arquivo XML salvo em
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>
Esse código de aplicativo recupera uma matriz de strings:
Kotlin
val array: Array
= resources
.getStringArray
(R.array.planets_array)Java
Resources res =
getResources()
; String[] planets = res.getStringArray
(R.array.planets_array);
Strings de quantidade (plurais)
Diferentes idiomas têm diferentes regras de concordância gramatical de número. Em inglês, por exemplo, a quantidade 1 é um caso especial. Escrevemos “1 livro”, mas, para qualquer outra quantidade, usamos “n livros”. Essa distinção entre singular e plural é muito comum, mas outros idiomas fazem distinções mais precisas. O conjunto completo permitido pelo Android é zero
, one
, two
, few
, many
e other
.
As regras para decidir qual caso usar para determinado idioma e quantidade podem ser muito complexas. Portanto, o Android fornece métodos como o getQuantityString()
para selecionar o recurso apropriado para você.
Apesar de serem historicamente chamadas de “strings de quantidade” (ainda chamadas assim na API), elas devem ser usadas somente para plurais. Seria um erro usar strings de quantidade para implementar algo como as strings “Inbox”/”Inbox (12)” do Gmail para quando há mensagens não lidas, por exemplo. Pode parecer conveniente usar strings de quantidade em vez de uma declaração if
. No entanto, é importante observar que alguns idiomas (como o chinês) não fazem essas distinções gramaticais. Por isso, você sempre receberá a string other
.
A seleção da string é feita exclusivamente com base na necessidade gramatical. No inglês, uma string para zero
será ignorada mesmo que a quantidade seja 0, já que 0 não é gramaticalmente diferente de 2 ou de qualquer número exceto 1 (“zero books”, “one book”, “two books” e assim por diante). Por outro lado, em coreano, somente a string other
é usada sempre.
Não se engane pelo fato de que, por exemplo, two
parece ser aplicável somente para a quantidade 2: um idioma pode exigir que 2, 12, 102 (e assim por diante) sejam tratados da mesma forma, mas de forma diferente de outras quantidades. Use seu tradutor como base para identificar quais são as distinções obrigatórias do idioma.
Frequentemente, é possível evitar strings de quantidade usando formulações de quantidade neutra, como “Books: 1”. Isso facilitará seu trabalho e o dos tradutores, caso seja um estilo compatível com seu aplicativo.
Observação: a coleção de plurais é um recurso simples referenciado com o valor fornecido no atributo name
(não o nome do arquivo XML). Dessa forma, você pode combinar plurais com outros recursos simples em um arquivo XML, em um elemento <resources>
.
- local do arquivo:
res/values/filename.xml
O atributo “filename” é arbitrário. Oname
do elemento<plurals>
é usado como o código do recurso.- referência do recurso:
-
Em Java:
R.plurals.plural_name
- sintaxe:
-
<?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>
- elementos:
- exemplo:
- Arquivo XML salvo em
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>
Arquivo XML salvo em
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>
Uso:
Kotlin
val count = getNumberOfSongsAvailable() val songsFound = resources.
getQuantityString
(R.plurals.numberOfSongsAvailable, count, count)Java
int count = getNumberOfSongsAvailable(); Resources res =
getResources()
; String songsFound = res.getQuantityString
(R.plurals.numberOfSongsAvailable, count, count);Ao usar o método
getQuantityString()
, você precisa passar ocount
duas vezes se a string contiver formatação com um número. Por exemplo, para a string%d songs found
, o primeiro parâmetrocount
seleciona a string plural apropriada, e o segundo parâmetrocount
é inserido no marcador%d
. Se as strings de plural não contiverem formatação de string, você não precisará passar o terceiro parâmetro paragetQuantityString
.
Formato e estilo
Apresentamos a seguir alguns itens importantes sobre como definir a formatação e o estilo dos seus recursos de string.
Gerenciar caracteres especiais
Quando uma string contém caracteres de uso especial em XML ou Android, eles precisam ter um escape. Alguns caracteres podem ter um escape com uma barra invertida anterior, enquanto outros exigem um escape com XML. Apóstrofos e aspas simples também podem ser gerenciados colocando toda a string entre aspas duplas. Veja alguns exemplos abaixo:
Caractere | Formas de escape |
---|---|
@ | \@ |
? | \? |
< | < |
& | & |
Aspas simples (' ) |
Qualquer um dos itens a seguir:
|
Aspas duplas (" ) |
Qualquer um dos itens a seguir:
Veja que as aspas duplas precisam ter um escape. Colocar a string entre aspas simples não funciona. |
Formatar strings
Se você precisar formatar suas strings, será possível colocar os argumentos de formato no recurso dela, conforme demonstrado pelo exemplo a seguir.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
Nesse exemplo, a string de formatação tem dois argumentos: %1$s
é uma string e %2$d
, é um número decimal. Depois, formate a string chamando getString(int, Object...)
. Por exemplo:
Kotlin
var text = getString(R.string.welcome_messages, username, mailCount)
Java
String text = getString(R.string.welcome_messages, username, mailCount);
Aplicar estilo com marcação HTML
Você pode adicionar estilo às suas strings com marcação HTML. Por exemplo:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
Os elementos HTML a seguir são compatíveis:
- Negrito: <b>, <em>
- Itálico: <i>, <cite>, <dfn>
- Texto 25% maior: <big>
- Texto 20% menor: <small>
- Configuração de propriedades de fonte: <font face=”font_family“ color=”hex_color”>. Exemplos de famílias de fontes podem incluir
monospace
,serif
esans_serif
. - Configuração de uma família de fontes de espaçamento uniforme: <tt>
- Tachado: <s>, <strike>, <del>
- Sublinhado: <u>
- Sobrescrito: <sup>
- Subscrito: <sub>
- Marcadores: <ul>, <li>
- Quebras de linha: <br>
- Divisão: <div>
- Estilo CSS: <span style=”color|background_color|text-decoration”>
- Parágrafos: <p dir=”rtl | ltr” style=”…”>
Se você não estiver aplicando uma formatação, poderá definir diretamente o texto do TextView chamando setText(java.lang.CharSequence)
. Em alguns casos, você poderá criar um recurso de texto com estilo que também é usado como uma string de formatação. Normalmente, isso não funciona porque os métodos format(String, Object...)
e getString(int, Object...)
tiram todas as informações de estilo da string. A solução para esse problema é criar tags HTML com entidades com escape, que são então recuperadas com fromHtml(String)
, após a realização da formatação. Por exemplo:
- Armazene seu recurso de texto com estilo como uma string HTML com escape:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
Nessa string formatada, é adicionado um elemento
<b>
. O colchete de abertura tem escape HTML usando a notação<
. - Em seguida, formate a string normalmente, mas também chame
fromHtml(String)
para converter o texto HTML em texto com estilo:Kotlin
val text: String = getString(R.string.welcome_messages, username, mailCount) val styledText: Spanned = Html.fromHtml(text, FROM_HTML_MODE_LEGACY)
Java
String text = getString(R.string.welcome_messages, username, mailCount); Spanned styledText = Html.fromHtml(text, FROM_HTML_MODE_LEGACY);
Como o método fromHtml(String)
formatará todas as entidades HTML, não deixe de executar o escape de qualquer caractere HTML possível nas strings usadas com o texto formatado usando htmlEncode(String)
. Por exemplo, se você pretende formatar uma string para que possa conter caracteres como “<” ou “&”, execute o escape antes da formatação para que a string formatada passe por fromHtml(String)
e os caracteres apareçam como foram escritos originalmente. Por exemplo:
Kotlin
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)
Java
String escapedUsername = TextUtils.htmlEncode
(username);
String text = getString(R.string.welcome_messages, escapedUsername, mailCount);
Spanned styledText = Html.fromHtml(text);
Criar estilo com spannables
Um Spannable
é um objeto de texto que pode receber estilo com propriedades typeface como cor e peso da fonte. O SpannableStringBuilder
é usado para compilar o texto e aplicar estilos definidos no pacote android.text.style
ao texto.
Você pode usar os seguintes métodos auxiliares para realizar grande parte da criação do texto spannable:
Kotlin
/** * 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) } } }
Java
/** * 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); } } }
Os métodos bold
, italic
e color
a seguir envolvem os métodos auxiliares acima e mostram exemplos específicos de aplicação de estilos definidos no pacote android.text.style
. Você pode criar métodos semelhantes para outros tipos de estilos de texto.
Kotlin
/** * 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))
Java
/** * 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)); }
Veja um exemplo de como agrupar esses métodos para aplicar vários estilos a palavras individuais em uma frase:
Kotlin
// 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)))
Java
// Create an italic "hello, " a red "world", // and bold the entire sequence. var text = bold(italic(getString(R.string.hello)), color(Color.RED, getString(R.string.world))) </pre> </section><section><h3 id="java">Java</h3> <pre class="prettyprint lang-java"> // 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)));
O módulo core-ktx do Kotlin também contém funções de extensão que facilitam ainda mais o trabalho com períodos. Confira a documentação do pacote android.text no GitHub para saber mais.
Para mais informações sobre como trabalhar com períodos, consulte os seguintes links:
Estilo com anotações
Você pode aplicar estilos complexos ou personalizados usando a classe Annotation
com a tag <annotation>
nos arquivos de recurso strings.xml. A tag de anotação permite marcar partes da string para estilo personalizado definindo pares de chave-valor personalizados no XML que a biblioteca converte em períodos da Annotation
. Você pode recuperar essas anotações e usar a chave e o valor para aplicar o estilo.
Ao criar anotações, adicione a tag <annotation>
para todas as traduções da string em todos os arquivos strings.xml.
Como aplicar um tipo de letra personalizado à palavra “texto” em todos os idiomas
Exemplo: com a adição de um typeface personalizado
-
Adicione uma tag
<annotation>
e defina o par de chave-valor. Nesse caso, a chave é font, e o valor é o tipo de fonte que queremos usar: 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>
-
Carregue o recurso da string e encontre as anotações com a chave font. Em seguida, crie um período personalizado e substitua o período existente.
Kotlin
// 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
Java
// get the text as SpannedString so we can get the spans attached to the text SpannedString titleText = (SpannedString) getText(R.string.title_about); // 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;
Se você estiver usando o mesmo texto várias vezes, deverá construir o objeto SpannableString uma vez e reutilizá-lo conforme necessário para evitar possíveis problemas de desempenho e memória.
Para mais exemplos de uso de anotações, consulte Como estilizar texto internacionalizado no Android
Períodos de anotação e parcelamento de texto
Como os períodos de Annotation
também são ParcelableSpans
, os pares de chave-valor são parcelados e não parcelados. Desde que o receptor da parcela saiba como interpretar as anotações, você pode usar períodos de Annotation
para aplicar estilos personalizados ao texto parcelado.
Para manter seu estilo personalizado ao passar o texto para um Intent Bundle, primeiro é necessário adicionar períodos de Annotation
ao texto. Você pode fazer isso nos recursos XML por meio da tag <annotation>, como mostrado no exemplo acima, ou no código, criando uma nova Annotation
e a configurando como um período, conforme exibido abaixo:
Kotlin
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)
Java
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);
Recupere o texto de Bundle
com uma SpannableString
e, em seguida, analise as anotações anexadas, conforme mostrado no exemplo acima.
Kotlin
// read text with Spans val intentCharSequence = intent.getCharSequenceExtra(TEXT_EXTRA) as SpannableString
Java
// read text with Spans SpannableString intentCharSequence = (SpannableString)intent.getCharSequenceExtra(TEXT_EXTRA);
Para mais informações sobre estilo de texto, consulte os seguintes links: