Jetpack Compose und styled strings.xml

Problem
Sie haben also einen Eintrag in strings.xml mit HTML-Inhalt:
<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))
}

Das ganze Styling ist weg! Was ist passiert?
Lösung
Jetpack Compose unterstützt noch keinen formatierten Text. Aber es ist einfach zu beheben.
Nach Ausgabe 139320238 erstellen wir unseren eigenen String-Ressourcenlader:
@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))
}

Äh was… Immer noch NICHT GESTYLT? Die Sache ist, dass der Vorschaumodus auch keinen formatierten Text unterstützt.
Aber ein echtes Gerät tut:

Und weil unsere Benutzer nur echte Geräte verwenden, geht es uns allen gut.
Unter der Haube
Jetpack Compose Text-Komponente unterstützt formatierten Text. Die Unterstützung heißt AnnotatedString. Wenn wir also nur Text mit AnnotatedStrings bereitstellen können, ist alles in Ordnung.
Auf der Android-Seite bietet es zwei Möglichkeiten, eine lokalisierte Zeichenfolge zu erhalten:
- String getString(id), der einen String zurückgibt. Das darf kein Styling enthalten und die HTML-Tags werden einfach weggelassen und ignoriert.
- CharSequence getText(id), das eine CharSequence zurückgibt. Der Haken an der Sache ist, dass diese Sequenz auch die in HTML definierten Style-Spans enthält.