https://kotlinlang.org logo
a

Alexander Karkossa

10/25/2020, 8:22 AM
Hey.
AnnotatedString
is what u are looking for. When the html tagged String is comming from resources (with
resources.getText
, not
resources.getString
), u could use these method.
Copy code
fun CharSequence.toAnnotatedString(urlSpanStyle: SpanStyle): AnnotatedString {
    return if (this is Spanned) {
        AnnotatedString.Builder().apply {
            append(toString())
            val urlSpans = getSpans<URLSpan>()
            val styleSpans = getSpans<StyleSpan>()
            val underlineSpans = getSpans<UnderlineSpan>()
            urlSpans.forEach { urlSpan ->
                val start = getSpanStart(urlSpan)
                val end = getSpanEnd(urlSpan)
                addStyle(urlSpanStyle, start, end)
                addStringAnnotation("url", urlSpan.url, start, end)
            }
            styleSpans.forEach { styleSpan ->
                val start = getSpanStart(styleSpan)
                val end = getSpanEnd(styleSpan)
                when (styleSpan.style) {
                    Typeface.BOLD -> addStyle(SpanStyle(fontWeight = FontWeight.Bold), start, end)
                    Typeface.ITALIC -> addStyle(SpanStyle(fontStyle = FontStyle.Italic), start, end)
                    Typeface.BOLD_ITALIC -> addStyle(SpanStyle(fontWeight = FontWeight.Bold, fontStyle = FontStyle.Italic), start, end)
                }
            }
            underlineSpans.forEach { underlineSpan ->
                val start = getSpanStart(underlineSpan)
                val end = getSpanEnd(underlineSpan)
                addStyle(SpanStyle(textDecoration = TextDecoration.Underline), start, end)
            }
        }.toAnnotatedString()
    } else {
        AnnotatedString(text = toString())
    }
}
You onle have to figure out, how to transfrom yout html tagged String from API to an
SpannableString
oder
SpannendString
. Makeing the string visible in compose:
Copy code
@Composable
fun HtmlText(
    modifier: Modifier = Modifier,
    @StringRes textId: Int,
    urlSpanStyle: SpanStyle = SpanStyle(
        color = MaterialTheme.colors.secondary,
        textDecoration = TextDecoration.Underline),
    textAlign: TextAlign = TextAlign.Start
) {
    val context = ContextAmbient.current
    val annotatedString = context.resources.getText(textId).toAnnotatedString(urlSpanStyle)

    val uriHandler = UriHandlerAmbient.current
    val layoutResult = remember { mutableStateOf<TextLayoutResult?>(null) }

    Text(
        modifier = modifier.tapGestureFilter { pos ->
            layoutResult.value?.let { layoutResult ->
                val position = layoutResult.getOffsetForPosition(pos)
                annotatedString.getStringAnnotations(position, position)
                    .firstOrNull()
                    ?.let { sa ->
                        if (sa.tag == "url") {
                            uriHandler.openUri(sa.item)
                        }
                    }
            }
        },
        onTextLayout = { layoutResult.value = it },
        text = annotatedString,
        textAlign = textAlign
    )
}
Hope this will help