Recursos de cadenas

Un recurso de cadenas ofrece cadenas de texto para tu aplicación con formato y estilo de texto opcionales. Existen tres tipos de recursos que pueden proporcionar strings para tu aplicación:

String
Recurso XML que ofrece una sola string.
Array de strings
Recurso XML que ofrece un array de strings.
Strings de cantidad (plurales)
Recurso XML que conlleva diferentes cadenas para brindar pluralización.

Todas las cadenas pueden aplicar algunos argumentos de formato y marcado de estilo. Para obtener información sobre las strings de formato y estilo, consulta la sección sobre Formato y estilo.

String

Una sola string a la cual se puede hacer referencia desde la aplicación o desde otros archivos de recursos (por ejemplo, un diseño XML).

Nota: Una string es un recurso simple al que se hace referencia utilizando el valor proporcionado en el atributo name (no el nombre del archivo en formato XML). De este modo, puedes combinar recursos de strings con otros recursos simples en el único archivo en formato XML, debajo de un elemento <resources>.

ubicación del archivo:
res/values/filename.xml
El nombre del archivo es arbitrario. El name del elemento de <string> se usa como ID del recurso.
tipo de datos de recursos compilados:
Puntero de recursos a un String.
referencia del recurso:
En Java: R.string.string_name
En XML:@string/string_name
sintaxis:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string
        name="string_name"
        >text_string</string>
</resources>
elementos:
<resources>
Obligatorio. Este debe ser el nodo raíz.

Sin atributos.

<string>
Cadena que puede incluir etiquetas de estilo. Ten en cuenta que se deben escapar los apóstrofos y las comillas. Para obtener más información sobre la manera de dar estilo y formato adecuadamente a tus strings, consulta Formato y estilo a continuación.

atributos:

name
String. Nombre para la string. El nombre se usa como ID del recurso.
ejemplo:
Archivo en formato XML guardado en res/values/strings.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello!</string>
</resources>

Este XML de diseño aplica una cadena a un objeto View:

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

Este código de aplicación recupera una string:

Kotlin

val string: String = getString(R.string.hello)

Java

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

Puedes usar getString(int) o getText(int) para recuperar una cadena. getText(int) retiene todo estilo de texto enriquecido aplicado a la string.

Array de strings

Array de cadenas al cual se puede hacer referencia desde la aplicación.

Nota: Un array de strings es un recurso simple al que se hace referencia mediante el valor proporcionado en el atributo name (no el nombre del archivo en formato XML). De este modo, puedes combinar recursos de array de strings con otros recursos simples en el único archivo en formato XML, debajo de un elemento <resources>.

ubicación del archivo:
res/values/filename.xml
El nombre del archivo es arbitrario. El name del elemento de <string-array> se usa como ID del recurso.
tipo de datos de recursos compilados:
Puntero de recurso para un elemento de array de Strings.
referencia del recurso:
En Java: R.array.string_array_name
En XML: @[package:]array/string_array_name
sintaxis:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array
        name="string_array_name">
        <item
            >text_string</item>
    </string-array>
</resources>
elementos:
<resources>
Obligatorio. Este debe ser el nodo raíz.

Sin atributos.

<string-array>
Define un array de strings. Contiene uno o más elementos <item>.

atributos:

name
String. Es un nombre para el array. El nombre se usa como ID del recurso para hacer referencia al array.
<item>
Cadena que puede incluir etiquetas de estilo. El valor puede ser una referencia a otro recurso de strings. Tiene que ser un elemento secundario de un elemento <string-array>. Ten en cuenta que se deben escapar los apóstrofos y las comillas. Consulta Formato y estilo a continuación para obtener información sobre cómo dar formato y estilo adecuadamente a tus strings.

Sin atributos.

ejemplo:
Archivo en formato XML guardado en 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>

Este código de aplicación obtiene un array de cadenas:

Kotlin

val array: Array<String> = resources.getStringArray(R.array.planets_array)

Java

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

Strings de cantidad (plurales)

Los diferentes idiomas tienen distintas reglas de concordancia gramatical con la cantidad. En inglés, por ejemplo, la cantidad 1 es un caso especial. Se escribe "1 book" (1 libro), pero, para las demás cantidades, se debe escribir "n books" (n libros). Esta distinción entre singular y plural es muy común; sin embargo, en otros idiomas, se hacen distinciones más detalladas. El conjunto completo compatible con Android es zero, one, two, few, many y other.

Las reglas para decidir el caso que se usará para un idioma y una cantidad determinados pueden ser muy complejas, por lo cual Android te proporciona métodos como getQuantityString() a fin de seleccionar el recurso adecuado para ti.

Si bien históricamente se llamaron "strings de cantidad" (y aún se llaman así en API), las strings de cantidad solo deben usarse para los plurales. Sería un error usar strings de cantidad para implementar algo como "Inbox" de Gmail en comparación con "Inbox (12)" cuando existen mensajes no leídos, por ejemplo. Podría parecer conveniente usar strings de cantidad en lugar de una instrucción if, pero es importante tener en cuenta que, en algunos idiomas (como el chino), no se hacen estas distinciones gramaticales en absoluto, por lo que siempre obtendrás la string other.

La selección de la string que se debe usar se realiza únicamente según la necesidad gramatical. En inglés, una string para zero se ignora incluso si la cantidad es 0, ya que 0 no es gramaticalmente diferente de 2 o cualquier otro número, excepto 1 ("zero books", "one book", "two books", y así sucesivamente). En cambio, en coreano, solo se usa la string other.

No te confundas por el hecho de que, por ejemplo, two suena como si solo pudiera aplicarse a la cantidad 2: un idioma puede requerir que 2, 12, 102 (y así sucesivamente) se traten de manera similar, pero de forma diferente de otras cantidades. Confía en tu traductor para conocer las distinciones de su idioma.

Si tu mensaje no contiene el número de cantidad, es probable que no sea un buen candidato para un plural. Por ejemplo, en lituano, la forma singular se usa para los números 1 y 101, por lo que "1 libro" se traduce como "1 knyga" y "101 libros" como "101 knyga". Mientras que "un libro" es "knyga", "muchos libros" es "daug knygų". Si un mensaje en inglés en plural incluye "un libro" (singular) y "muchos libros" (plural) sin el número real, se puede traducir como "knyga" (un libro)/"daug knygų" (muchos libros), pero con las reglas del lituano, se mostrará "knyga" (un solo libro) cuando el número sea 101.

En ocasiones, es posible evitar las strings de cantidad usando fórmulas de cantidad neutra, por ejemplo "Books: 1" (Libros: 1). Esto hará más fáciles las cosas para ti y tus traductores si se trata de un estilo aceptable para tu aplicación.

En el nivel de API 24 y versiones posteriores, puedes usar la clase MessageFormat de ICU mucho más potente en su lugar.

Nota: Una colección de plurales es un recurso simple al que se hace referencia utilizando el valor proporcionado en el atributo name (no el nombre del archivo en formato XML). Por eso, puedes combinar recursos de plurales con otros recursos simples en un archivo en formato XML, en un elemento <resources>.

ubicación del archivo:
res/values/filename.xml
El nombre del archivo es arbitrario. El name del elemento de <plurals> se usa como ID del recurso.
referencia del recurso:
En Java: R.plurals.plural_name
sintaxis:
<?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:
<resources>
Obligatorio. Este debe ser el nodo raíz.

Sin atributos.

<plurals>
Una colección de strings, de las cuales se proporciona una string según la cantidad de algún elemento. Contiene uno o más elementos <item>.

atributos:

name
String. Nombre para el par de strings. El nombre se usa como ID del recurso.
<item>
Una string singular o plural. El valor puede ser una referencia a otro recurso de strings. Tiene que ser un elemento secundario de un elemento <plurals>. Ten en cuenta que se deben escapar los apóstrofos y las comillas. Consulta Formato y estilo a continuación para obtener información sobre cómo dar formato y estilo adecuadamente a tus strings.

atributos:

quantity
Palabra clave. Valor que indica cuándo debe usarse esta string. Valores válidos, con ejemplos no exhaustivos entre paréntesis:
ValorDescripción
zeroCuando el idioma requiere tratamiento especial del número 0 (como en árabe).
oneCuando el idioma requiere tratamiento especial de números como el uno (como el número 1 en inglés y la mayoría de los demás idiomas; en ruso, se encuentran dentro de esta clase todos los números que finalizan en 1, pero no en 11).
twoCuando el idioma requiere tratamiento especial de números como el dos (como el 2 en galés, o el 102 en esloveno).
fewCuando el idioma requiere tratamiento especial de números "pequeños" (como el 2, el 3 y el 4 en checo, o los números que finalizan en 2, 3 o 4, excepto el 12, el 13 o el 14 en polaco).
manyCuando el idioma requiere tratamiento especial de números "grandes" (como los números que finalizan en 11-99 en maltés).
otherCuando el idioma no requiere tratamiento especial de la cantidad especificada (como todos los números en chino o el 42 en inglés).
ejemplo:
Archivo en formato XML guardado en 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>

Archivo en formato XML guardado en 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);

Cuando se usa el método getQuantityString(), debes pasar count dos veces si tu string incluye formato de string con un número. Por ejemplo, para la string %d songs found, el primer parámetro de count selecciona el plural adecuado, y el segundo parámetro de count se inserta en el marcador de posición %d. Si tus strings de plural no incluyen formato de string, no es necesario que pases el tercer parámetro a getQuantityString.

Formato y estilo

A continuación, se mencionan algunos puntos importantes que debes conocer sobre cómo dar formato y estilo adecuadamente a tus recursos de strings.

Caracteres especiales

Cuando una string contiene caracteres que se usan de manera especial en XML, debes escapar los caracteres de acuerdo con las reglas de escape estándar en XML/HTML. Si necesitas escapar un carácter que tiene un significado especial en Android, debes usar antes una barra inversa.

De forma predeterminada, Android contraerá secuencias de caracteres de espacios en blanco en un solo espacio. Para evitar esto, encierra la parte relevante de la string entre comillas dobles. En este caso, todos los caracteres de espacios en blanco (incluidas las nuevas líneas) se conservarán dentro de la región entrecomillada. Las comillas dobles también te permitirán usar comillas simples regulares sin escapar.

Carácter Formas de escape
@ \@
? \?
Nueva línea \n
Tab \t
carácter Unicode U+XXXX \uXXXX
Comilla simple (')

Cualquiera de los siguientes:

  • \'
  • Encierra toda la string entre comillas dobles ("This'll work", por ejemplo)
Comillas dobles (") \"

Ten en cuenta que encerrar la string entre comillas simples no funciona.

La contracción del espacio en blanco y el escape de Android ocurren después de que se analiza tu archivo de recursos como XML. Es decir, <string> &#32; &#8200; &#8195;</string> (espacio, espacio de puntuación, espacio largo de Unicode) se contraen a un solo espacio (" "), ya que son todos espacios de Unicode después de que se analiza el archivo como XML. Para conservar esos espacios como están, puedes entrecomillarlos (<string>" &#32; &#8200; &#8195;"</string>) o usar el escape de Android (<string> \u0032 \u8200 \u8195</string>).

Nota: Desde la perspectiva del analizador XML, no hay diferencia algunas entre <string>"Test this"</string> y <string>&quot;Test this&quot;</string>. Ambos formularios no mostrarán comillas, pero activarán las que preservan los espacios en blanco de Android (que no tendrá un efecto práctico en este caso).

Cómo dar formato a las strings

Si necesitas dar formato a tus strings, puedes hacerlo disponiendo tus argumentos de formato en el recurso de strings, tal como se demuestra en el siguiente recurso de ejemplo:

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

En este ejemplo, la string de formato tiene dos argumentos: %1$s es una string y %2$d es un número decimal. Entonces, dale formato a la string llamando a getString(int, Object...). Por ejemplo:

Kotlin

var text = getString(R.string.welcome_messages, username, mailCount)

Java

String text = getString(R.string.welcome_messages, username, mailCount);

Cómo dar estilo con el lenguaje de marcado HTML

Puedes agregar estilo a tus strings con el lenguaje de marcado HTML. Por ejemplo:

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

Se admiten los siguientes elementos HTML:

  • Negrita: <b>
  • Cursiva: <i>, <cite>, <dfn>, <em>
  • Texto 25% más grande: <big>
  • Texto 20% más pequeño: <small>
  • Configurar propiedades de la fuente: <font face=”font_family“ color=”hex_color”>. Algunas familias de fuentes posibles son monospace, serif y sans_serif.
  • Configurar una familia de fuentes monoespacio: <tt>
  • Tachado: <s>, <strike>, <del>
  • Subrayado: <u>
  • Superíndice: <sup>
  • Subíndice: <sub>
  • Viñetas: <ul>, <li>
  • Saltos de línea: <br>
  • División: <div>
  • Estilo CSS: <span style=”color|background_color|text-decoration”>
  • Párrafos: <p dir=”rtl | ltr” style=”…”>

Si decides no aplicar formato, puedes llamar a setText(java.lang.CharSequence) para establecer el texto de TextView directamente. Sin embargo, en algunos casos, es posible que desees crear un recurso de texto con estilo que también se use como string de formato. Generalmente, esto no funciona porque los métodos format(String, Object...) y getString(int, Object...) quitan toda la información de estilo de la string. La solución temporal para esto es escribir las etiquetas HTML con entidades escapadas, que se recuperan después con fromHtml(String) una vez que se lleva a cabo el formato. Por ejemplo:

  1. Almacena tu recurso de texto con estilo como una cadena escapada con HTML:
    <resources>
      <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d new messages&lt;/b>.</string>
    </resources>
    

    En esta cadena con formato, se agrega un elemento <b>. Ten en cuenta que el corchete de apertura está con escape HTML mediante la anotación &lt;.

  2. Luego, da formato a la string como siempre, pero también llama a fromHtml(String) para convertir el texto HTML en texto con 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);
    

Debido a que el método fromHtml(String) da formato a todas las entidades HTML, asegúrate de escapar todos los caracteres HTML posibles en las strings que usas con el texto con formato mediante htmlEncode(String). Por ejemplo, si das formato a una string que contiene caracteres como "<" o "&", se deben escapar antes de dar formato, de modo que, cuando se pase la string con formato por fromHtml(String) los caracteres aparezcan como se escribieron originalmente. Por ejemplo:

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);

Cómo dar estilo con Spannable

Un Spannable es un objeto de texto al cual puedes dar estilo con propiedades de tipos de letras, como color y tamaño de las fuentes. Usas SpannableStringBuilder a fin de crear tu texto y, luego, aplicar estilos definidos en el paquete de android.text.style para el texto.

Puedes usar los siguientes métodos auxiliares para configurar gran parte del trabajo de crear texto de 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);
        }
    }
}

Los siguientes métodos bold, italic y color contienen los métodos de ayuda anteriores y permiten ver ejemplos específicos de cómo dar estilos definidos en el paquete android.text.style. Puedes crear métodos similares para dar otros tipos de estilos al 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));
}

Este es un ejemplo de cómo encadenar estos métodos a fin de aplicar diversos estilos a palabras específicas en una 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.
CharSequence text = bold(italic(getString(R.string.hello)),
    color(Color.RED, getString(R.string.world)));

El módulo core-ktx de Kotlin también contiene funciones de extensión que facilitan mucho más el trabajo con intervalos. Para obtener más información, puedes consultar la documentación sobre el paquete android.text en GitHub.

Para obtener más información sobre el trabajo con intervalos, consulta estos enlaces:

Cómo dar estilo con anotaciones

Puedes aplicar estilos complejos o personalizados si usas la clase Annotation junto con la etiqueta <annotation> en tus archivos de recursos strings.xml. La etiqueta de anotación permite marcar partes de la string a fin de darles un estilo personalizado. Para hacerlo, deben definirse pares clave-valor personalizados en el XML que el framework convertirá en intervalos de Annotation. Después, puedes recuperar estas anotaciones y usar la clave y el valor para aplicar el estilo.

Cuando creas anotaciones, asegúrate de agregar la etiqueta <annotation> a todas las traducciones de la string en cada archivo strings.xml.


Aplicar un tipo de letra personalizado a la palabra "texto" en todos los idiomas

Ejemplo: Agregar un tipo de letra personalizado

  1. Agrega la etiqueta <annotation> y define el par clave-valor. En este caso, la clave es font y el valor es el tipo de fuente 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>
    
  2. Carga el recurso de strings y busca las anotaciones con la clave font. Después, crea un intervalo personalizado y reemplaza el 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);
    
    // 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;
    

Si usas el mismo texto varias veces, debes construir el objeto SpannableString una vez y volver a usarlo cuando lo necesites. Así evitarás posibles problemas de rendimiento y memoria.

Para conocer otros ejemplos del uso de anotaciones, consulta Dar estilo a texto internacional en Android.

Intervalos de anotación y parcelas de texto

Dado que los intervalos de Annotation también son ParcelableSpans, los pares clave-valor pueden dividirse y reunirse en parcelas. Siempre y cuando el receptor de la parcela sepa cómo interpretar las anotaciones, puedes usar intervalos de Annotation para aplicar estilos personalizados al texto en parcelas.

Para mantener el estilo personalizado cuando pasas el texto a un conjunto de intents, primero debes agregar a tu texto intervalos de Annotation. Puedes hacerlo en los recursos XML usando la etiqueta <annotation> (como se muestra en el ejemplo anterior) o en el código, creando una nueva Annotation y definiéndola como intervalo, tal como se ejemplifica a continuación:

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);

Recupera el texto del Bundle como una SpannableString y, luego, divide las anotaciones adjuntas, tal como se ejemplificó anteriormente.

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 obtener más información sobre cómo dar estilo al texto, consulta los siguientes enlaces: