Jetpack Compose e strings.xml com estilo

Nov 26 2022
Problema Então você tem uma entrada em strings.xml com conteúdo HTML: Todo o estilo desapareceu! O que aconteceu? Solução O Jetpack Compose ainda não é compatível com texto estilizado.
Logotipo do Jetpack Compose. Parece bom, mas não tem texto estilizado. Por que é que?

Problema

Então você tem uma entrada em strings.xml com conteúdo 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))
}

Prévia do texto. Falta estilo!

Todo o estilo se foi! O que aconteceu?

Solução

O Jetpack Compose ainda não é compatível com texto estilizado. Mas é simples de consertar.

Após o problema 139320238 , criamos nosso próprio carregador de recursos de string:

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

Prévia do texto. Ainda sem estilo, porque não é compatível com o Preview

Eh o que… Ainda NÃO ESTILIZADO? O problema é que o modo de visualização também não oferece suporte a texto estilizado.

Mas, um dispositivo real faz:

Visualização de texto em um dispositivo. O estilo está aí!

E como nossos usuários usam apenas dispositivos reais, estamos todos bem.

Sob o capô

O componente Jetpack Compose Text oferece suporte a texto com estilo. O suporte é chamado de AnnotatedString. Então, se pudermos apenas fornecer Text com AnnotatedStrings, estamos todos bem.

Do lado do Android, ele fornece duas maneiras de obter uma string localizada:

  • String getString(id), que retorna uma String. Isso não pode conter nenhum estilo e as tags HTML são simplesmente descartadas e ignoradas.
  • CharSequence getText(id), que retorna um CharSequence. O problema é que essa sequência também contém os intervalos de estilo definidos em HTML.