3. 可点击文本链接样式
ClickableText 与 Modifier.clickable 的差异
在 Compose 中为文本添加点击事件有两条路径:ClickableText 是专门为文本设计的可组合项,它把点击位置映射为字符偏移量(offset),适合需要知道"用户点了哪个字"的场景;Modifier.clickable 则把整段文本当作一个整体点击区域,适合"整行文字即一个链接"的简单交互。两者在回调参数、点击粒度、视觉反馈上都有明显区别。
ClickableText 实现多链接文本
下面这段代码把一段包含两个链接的文本渲染出来,点击"官网"和"文档"分别触发不同回调。关键点在于用 AnnotatedString 标记链接区间,再在 onClick 中根据 offset 判断落在哪个区间。
@Composable
fun MultiLinkText() {
val linkColor = Color(0xFF1A73E8)
val annotated = buildAnnotatedString {
append("访问 ")
withStyle(SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline)) {
pushStringAnnotation(tag = "URL", annotation = "https://example.com")
append("官网")
pop()
}
append(" 或查看 ")
withStyle(SpanStyle(color = linkColor, textDecoration = TextDecoration.Underline)) {
pushStringAnnotation(tag = "URL", annotation = "https://docs.example.com")
append("文档")
pop()
}
append(" 了解更多。")
}
ClickableText(
text = annotated,
style = TextStyle(fontSize = 16.sp, color = Color(0xFF333333)),
onClick = { offset ->
annotated.getStringAnnotations(tag = "URL", start = offset, end = offset)
.firstOrNull()?.let { annotation ->
// 此处处理点击回调,例如打开浏览器或更新状态
println("点击链接: ${annotation.item}")
}
}
)
}
offset 边界注意:当点击位置恰好落在两个链接之间的空白字符上时,
getStringAnnotations 返回空列表,此时不应触发任何链接回调。建议在 let 之前先判断结果是否为空,避免误触。
Modifier.clickable 实现整行链接
如果整段文本就是一个链接,用 Modifier.clickable 更简洁,而且自带涟漪反馈。注意 clickable 需要配合 indication 和 interactionSource 才能获得默认涟漪效果(在 Material3 中通常由 Modifier.clickable 的默认参数提供)。
@Composable
fun WholeLineLink(onClick: () -> Unit) {
Text(
text = "查看完整文档 →",
color = Color(0xFF1A73E8),
textDecoration = TextDecoration.Underline,
fontSize = 16.sp,
modifier = Modifier
.clickable { onClick() }
.padding(vertical = 8.dp, horizontal = 4.dp)
)
}
两种方式的选择依据
| 判断维度 | ClickableText | Modifier.clickable |
|---|---|---|
| 点击粒度 | 字符级(offset) | 整体区域 |
| 回调参数 | (Int) → Unit | () → Unit |
| 多链接支持 | 原生支持,需手动判断区间 | 需拆成多个 Text 组合 |
| 涟漪反馈 | 无默认涟漪 | 默认带涟漪 |
| 适用场景 | 富文本内嵌多个链接 | 整行/整块文字作为单一链接 |
常见问题:使用
ClickableText 时如果忘记在 onClick 中做 offset 区间判断,会导致点击任意位置都触发同一个回调。务必用 getStringAnnotations 或手动比较 offset 范围来区分不同链接。