Jetpack Compose und styled strings.xml

Nov 26 2022
Problem Sie haben also einen Eintrag in strings.xml mit HTML-Inhalt: Das ganze Styling ist weg! Was ist passiert? Lösung Jetpack Compose unterstützt noch keinen formatierten Text.
Jetpack Compose-Logo. Es sieht gut aus, hat aber keinen formatierten Text. Warum das?

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

Vorschau des Textes. Styling fehlt!

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

Vorschau des Textes. Immer noch kein Styling, da es in der Vorschau nicht unterstützt wird

Äh was… Immer noch NICHT GESTYLT? Die Sache ist, dass der Vorschaumodus auch keinen formatierten Text unterstützt.

Aber ein echtes Gerät tut:

Vorschau von Text auf einem Gerät. Styling ist da!

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.