Jetpack Compose Text 超链接部分文本
Posted
技术标签:
【中文标题】Jetpack Compose Text 超链接部分文本【英文标题】:Jetpack Compose Text hyperlink some section of the 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
)
【问题讨论】:
【参考方案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,
),
)
截图,
注意
-
我正在使用可组合项手动处理网页。如果不需要手动控制,请使用
UriHandler
或其他替代方法。
LinkText
中要求的可点击和其他文本样式。
【讨论】:
tag
有什么用?
@Marat, tag
就像 id。用于识别注解 - 文档:developer.android.com/reference/kotlin/androidx/compose/ui/text/…
我明白了。非常感谢【参考方案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进行链接检测,与TextView
的autoLink
相同。
【讨论】:
以上是关于Jetpack Compose Text 超链接部分文本的主要内容,如果未能解决你的问题,请参考以下文章
Jetpack Compose 无限加载列表(滚到底部自动加载更多)