【问题标题】:Jetpack Compose Text hyperlink some section of the textJetpack Compose Text 超链接部分文本
【发布时间】:2021-04-10 12:36:49
【问题描述】:

如何在 Text 组件的部分文本中添加超链接?

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

   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
)

【问题讨论】:

    标签: android android-jetpack-compose android-jetpack-compose-text


    【解决方案1】:

    要获得完整的答案,您可以使用返回文本位置的ClickableText,并使用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)
                }
        }
    )
    

    【讨论】:

    • 如何使用字符串资源进行这项工作,这似乎是硬编码字符串的好方法。
    【解决方案2】:

    标注的答案让新手很困惑,我举个完整的例子

    请不要忘记以pop()结束pushStringAnnotation

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

    最终效果

    【讨论】:

    • 不错!您只是忘记在第一个 pushStringAnnotation 和 withStyle 方法对之后调用 pop()。
    • 有没有办法为这样的视图添加一些选定的状态/涟漪效果?现在它看起来完全是静态的
    • @ZdenekSima 谢谢提醒,我更新了答案
    【解决方案3】:

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

    创建一个新文件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 中要求的可点击和其他文本样式。

    【讨论】:

    【解决方案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
        )
    }
    

    标签:用于区分注解的标签

    annotation:附加的字符串注解

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

    end

    的独占结束偏移量

    Source

    【讨论】:

    • 除了“URL”还有什么其他标签?
    • 对不起。我误解了。我也是刚学的。它需要4个参数。谢谢你的好问题。
    • 我用 annotatedString() 尝试了这个并设置为Text,添加了互联网权限以显示但它不起作用,我的意思是当你触摸文本时什么都没有发生。介意检查一下吗?
    • 您需要使用 url 处理程序。
    【解决方案5】:

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

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

    另外,它使用Android的Linkify进行链接检测,与TextViewautoLink相同。

    【讨论】:

      猜你喜欢
      • 2021-11-07
      • 1970-01-01
      • 2020-12-22
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2022-10-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多