m

    Mouaad

    1 year ago
    Hi, is there any way, right now, to render a String with html tag? (the string itself is coming from an API)
    Alexander Karkossa

    Alexander Karkossa

    1 year ago
    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.
    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:
    @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
    m

    Mouaad

    1 year ago
    I will give this a try, thank you!
    Alexander Karkossa

    Alexander Karkossa

    1 year ago
    Maybe Html.fromHtml(stringFromApi) could transform your String into Spanned
    The html is parsed via jsoup