Jetpack Composer et styliser strings.xml

Nov 26 2022
Problème Vous avez donc une entrée dans strings.xml avec du contenu HTML : tout le style a disparu ! Qu'est-il arrivé? Solution Jetpack Compose ne prend pas encore en charge le texte stylisé.
Logo Jetpack Compose. Il a l'air bien, mais n'a pas de texte stylé. Pourquoi donc?

Problème

Vous avez donc une entrée dans strings.xml avec du contenu 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))
}

Aperçu du texte. Le style manque !

Tout le style est parti! Qu'est-il arrivé?

La solution

Jetpack Compose ne prend pas encore en charge le texte stylisé. Mais c'est simple à réparer.

Suite au problème 139320238 , nous créons notre propre chargeur de ressources de chaîne :

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

Aperçu du texte. Toujours pas de style, car il n'est pas pris en charge dans Preview

Eh quoi… Toujours PAS DE STYLE ? Le fait est que le mode Aperçu ne prend pas non plus en charge le texte stylé.

Mais, un vrai appareil fait :

Aperçu du texte sur un appareil. Le style est là !

Et parce que nos utilisateurs n'utilisent que de vrais appareils, nous allons tous bien.

Sous la capuche

Le composant Jetpack Compose Text prend en charge le texte stylisé. Le support est appelé AnnotatedString. Donc, si nous pouvons simplement fournir du texte avec AnnotatedStrings, tout va bien.

Du côté Android, il propose deux façons d'obtenir une chaîne localisée :

  • String getString(id), qui renvoie une chaîne. Cela ne peut contenir aucun style et les balises HTML sont simplement supprimées et ignorées.
  • CharSequence getText(id), qui renvoie un CharSequence. Le hic, c'est que cette séquence contient également les étendues de style définies en HTML.