27

如何将超链接添加到 Text 组件文本的某些部分?

buildAnnotatedString可以将链接部分设置为蓝色并加下划线,如下图所示,但我怎样才能将该部分转换为链接?

在此处输入图像描述

   val annotatedLinkString = buildAnnotatedString {
        val str = "Click this link to go to web site"
        val startIndex = str.indexOf("link")
        val endIndex = startIndex + 4
        append(str)
        addStyle(
            style = SpanStyle(
                color = Color(0xff64B5F6),
                textDecoration = TextDecoration.Underline
            ), start = startIndex, end = endIndex
        )
    }

    Text(
        modifier = modifier
            .padding(16.dp)
            .fillMaxWidth(),
        text = annotatedLinkString
    )

我也可以得到Spanned,但有什么方法可以使用它Text吗?

val str: Spanned = HtmlCompat.fromHtml(
    "<a href=\"http://www.github.com\">Github</a>", HtmlCompat.FROM_HTML_MODE_LEGACY
)
4

5 回答 5

37

要获得完整的答案,您可以使用ClickableTextwhich 返回文本的位置,并UriHandler在浏览器中打开 URI。

val annotatedLinkString: AnnotatedString = buildAnnotatedString {

    val str = "Click this link to go to web site"
    val startIndex = str.indexOf("link")
    val endIndex = startIndex + 4
    append(str)
    addStyle(
        style = SpanStyle(
            color = Color(0xff64B5F6),
            fontSize = 18.sp,
            textDecoration = TextDecoration.Underline
        ), start = startIndex, end = endIndex
    )

    // attach a string annotation that stores a URL to the text "link"
    addStringAnnotation(
        tag = "URL",
        annotation = "https://github.com",
        start = startIndex,
        end = endIndex
    )

}

// UriHandler parse and opens URI inside AnnotatedString Item in Browse
val uriHandler = LocalUriHandler.current

//  Clickable text returns position of text that is clicked in onClick callback
ClickableText(
    modifier = modifier
        .padding(16.dp)
        .fillMaxWidth(),
    text = annotatedLinkString,
    onClick = {
        annotatedLinkString
            .getStringAnnotations("URL", it, it)
            .firstOrNull()?.let { stringAnnotation ->
                uriHandler.openUri(stringAnnotation.item)
            }
    }
)
于 2021-01-10T17:36:31.473 回答
19

标记的答案让新手感到困惑,我举一个完整的例子

请不要忘记pushStringAnnotation pop()

val annotatedString = buildAnnotatedString {
    append("By joining, you agree to the ")

    pushStringAnnotation(tag = "policy", annotation = "https://google.com/policy")
    withStyle(style = SpanStyle(color = MaterialTheme.colors.primary)) {
        append("privacy policy")
    }
    pop()

    append(" and ")

    pushStringAnnotation(tag = "terms", annotation = "https://google.com/terms")

    withStyle(style = SpanStyle(color = MaterialTheme.colors.primary)) {
        append("terms of use")
    }

    pop()
}

ClickableText(text = annotatedString, style = MaterialTheme.typography.body1, onClick = { offset ->
    annotatedString.getStringAnnotations(tag = "policy", start = offset, end = offset).firstOrNull()?.let {
        Log.d("policy URL", it.item)
    }

    annotatedString.getStringAnnotations(tag = "terms", start = offset, end = offset).firstOrNull()?.let {
        Log.d("terms URL", it.item)
    }
})

最终效果

在此处输入图像描述

于 2021-10-13T04:54:52.907 回答
6

对于任何寻找可重复使用的复制粘贴解决方案的人,

创建一个新文件LinkText.kt并复制粘贴此代码,

data class LinkTextData(
    val text: String,
    val tag: String? = null,
    val annotation: String? = null,
    val onClick: ((str: AnnotatedString.Range<String>) -> Unit)? = null,
)

@Composable
fun LinkText(
    linkTextData: List<LinkTextData>,
    modifier: Modifier = Modifier,
) {
    val annotatedString = createAnnotatedString(linkTextData)

    ClickableText(
        text = annotatedString,
        style = MaterialTheme.typography.body1,
        onClick = { offset ->
            linkTextData.forEach { annotatedStringData ->
                if (annotatedStringData.tag != null && annotatedStringData.annotation != null) {
                    annotatedString.getStringAnnotations(
                        tag = annotatedStringData.tag,
                        start = offset,
                        end = offset,
                    ).firstOrNull()?.let {
                        annotatedStringData.onClick?.invoke(it)
                    }
                }
            }
        },
        modifier = modifier,
    )
}

@Composable
private fun createAnnotatedString(data: List<LinkTextData>): AnnotatedString {
    return buildAnnotatedString {
        data.forEach { linkTextData ->
            if (linkTextData.tag != null && linkTextData.annotation != null) {
                pushStringAnnotation(
                    tag = linkTextData.tag,
                    annotation = linkTextData.annotation,
                )
                withStyle(
                    style = SpanStyle(
                        color = MaterialTheme.colors.primary,
                        textDecoration = TextDecoration.Underline,
                    ),
                ) {
                    append(linkTextData.text)
                }
                pop()
            } else {
                append(linkTextData.text)
            }
        }
    }
}

用法

LinkText(
    linkTextData = listOf(
        LinkTextData(
            text = "Icons made by ",
        ),
        LinkTextData(
            text = "smalllikeart",
            tag = "icon_1_author",
            annotation = "https://www.flaticon.com/authors/smalllikeart",
            onClick = {
                Log.d("Link text", "${it.tag} ${it.item}")
            },
        ),
        LinkTextData(
            text = " from ",
        ),
        LinkTextData(
            text = "Flaticon",
            tag = "icon_1_source",
            annotation = "https://www.flaticon.com/",
            onClick = {
                Log.d("Link text", "${it.tag} ${it.item}")
            },
        )
    ),
    modifier = Modifier
        .padding(
            all = 16.dp,
        ),
)

截图

截屏

笔记

  1. 我正在使用可组合手动处理网页。UriHandler如果不需要手动控制,请使用或其他替代方法。
  2. 根据LinkText.
于 2021-10-19T19:41:33.257 回答
4

如何将超链接添加到 Text 组件文本的某些部分?

with(AnnotatedString.Builder()) {
    append("link: Jetpack Compose")
    // attach a string annotation that stores a URL to the text "Jetpack Compose".
    addStringAnnotation(
        tag = "URL",
        annotation = "https://developer.android.com/jetpack/compose",
        start = 6,
        end = 21
    )
}

tag:用于区分注解的标签

annotation:附加的字符串注释

start:范围的包含起始偏移量

end : 的唯一结束偏移量

来源

于 2021-01-04T19:15:19.053 回答
4

您可以使用https://github.com/firefinchdev/linkify-text

它是一个文件,您可以直接将其复制到您的项目中。

另外,它使用 Android 的Linkify进行链接检测,与TextView's 的一样autoLink

于 2021-11-26T16:26:17.270 回答