Jetpack Compose y strings.xml con estilo

Problema
Así que tienes una entrada en strings.xml con contenido HTML:
<string name="neatly_styled">Nice <u>underlined</u> and <b>bold</b> text.</string>
@Preview
@Compose
fun PreviewStyledText() {
Text(text = stringResource(R.string.neatly_styled))
}

¡Todo el estilo se ha ido! ¿Qué sucedió?
Solución
Jetpack Compose aún no admite texto con estilo. Pero es fácil de arreglar.
Siguiendo el problema 139320238 , creamos nuestro propio cargador de recursos de cadena:
@Composable
fun annotatedStringResource(@StringRes id: Int): AnnotatedString {
val resources = LocalContext.current.resources
return remember(id) {
val text = resources.getText(id)
if (text is Spanned) {
val spanStyles = mutableListOf<AnnotatedString.Range<SpanStyle>>()
spanStyles.addAll(text.getSpans(0, text.length, UnderlineSpan::class.java).map {
AnnotatedString.Range(
SpanStyle(textDecoration = TextDecoration.Underline),
text.getSpanStart(it),
text.getSpanEnd(it)
)
})
spanStyles.addAll(text.getSpans(0, text.length, StyleSpan::class.java).map {
AnnotatedString.Range(
SpanStyle(fontWeight = FontWeight.Bold),
text.getSpanStart(it),
text.getSpanEnd(it)
)
})
AnnotatedString(text.toString(), spanStyles = spanStyles)
} else {
AnnotatedString(text.toString())
}
}
}
@Preview
@Composable
fun PreviewStyledTextFix() {
Text(text = annotatedStringResource(R.string.styled_text))
}

Eh qué… ¿Aún NO ESTÁS ESTILO? La cuestión es que el modo de vista previa tampoco admite texto con estilo.
Pero, un dispositivo real sí:

Y como nuestros usuarios solo usan dispositivos reales, todos estamos bien.
Bajo el capó
El componente Jetpack Compose Text admite texto con estilo. El soporte se llama AnnotatedString. Entonces, si podemos proporcionar Texto con AnnotatedStrings, todo está bien.
Desde el lado de Android, proporciona dos formas de obtener una cadena localizada:
- String getString(id), que devuelve un String. Eso no puede contener ningún estilo y las etiquetas HTML simplemente se eliminan y se ignoran.
- CharSequence getText(id), que devuelve una CharSequence. El problema es que esta secuencia también contiene los intervalos de estilo definidos en HTML.