You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为AnnotatedString中指定绿色文字添加独立Tooltip?

在Jetpack Compose中为文本片段添加独立Tooltip的最优方案

核心思路

利用AnnotatedString的自定义注解存储每个术语的Tooltip内容,结合ClickableText捕获点击事件,从注解中提取对应解释并触发弹窗,避免手动维护偏移量列表。

实现步骤

1. 定义自定义注解类

用来存储每个术语的Tooltip解释:

data class TooltipAnnotation(val explanation: String) : Annotation

2. 构建带注解和样式的AnnotatedString

将用户输入文本中的术语标记为绿色,并绑定对应的Tooltip注解:

fun buildAnnotatedText(
    inputText: String,
    termExplanations: Map<String, String> // 术语到解释的映射,比如{"Compose": "Google的声明式UI框架"}
): AnnotatedString {
    val builder = AnnotatedString.Builder()
    var currentPos = 0

    // 遍历所有术语,插入带样式和注解的文本片段
    termExplanations.forEach { (term, explanation) ->
        val termStart = inputText.indexOf(term, currentPos)
        if (termStart != -1) {
            // 添加术语前的普通文本
            builder.append(inputText.substring(currentPos, termStart))
            // 推送绿色文本样式
            builder.pushStyle(TextStyle(color = Color.Green).toSpanStyle())
            // 推送Tooltip注解
            builder.pushAnnotation(
                tag = "TERM_TOOLTIP",
                annotation = TooltipAnnotation(explanation)
            )
            builder.append(term)
            // 弹出注解和样式
            builder.pop()
            builder.pop()
            currentPos = termStart + term.length
        }
    }
    // 添加剩余的文本
    builder.append(inputText.substring(currentPos))
    return builder.toAnnotatedString()
}

3. 实现带Tooltip的可点击文本组件

通过ClickableText捕获点击,提取注解内容并显示弹窗:

@Composable
fun TermTooltipText(annotatedText: AnnotatedString) {
    var isTooltipVisible by remember { mutableStateOf(false) }
    var currentTooltipContent by remember { mutableStateOf("") }

    Box {
        ClickableText(
            text = annotatedText,
            onClick = { clickOffset ->
                // 获取点击位置对应的Tooltip注解
                annotatedText.getStringAnnotations(
                    tag = "TERM_TOOLTIP",
                    start = clickOffset,
                    end = clickOffset
                ).firstOrNull()?.let { annotation ->
                    currentTooltipContent = (annotation.item as TooltipAnnotation).explanation
                    isTooltipVisible = true
                } ?: run {
                    isTooltipVisible = false
                }
            }
        )

        // 显示Tooltip弹窗
        if (isTooltipVisible) {
            RichTooltipBox(
                onDismissRequest = { isTooltipVisible = false },
                tooltip = {
                    RichTooltip(
                        title = { Text("术语解释") },
                        text = { Text(currentTooltipContent) }
                    )
                }
            ) {
                // 空内容,仅用于触发Tooltip逻辑
            }
            // 若需自定义弹窗样式,可替换为Popup组件
            /*
            Popup(
                alignment = Alignment.TopCenter,
                offset = IntOffset(0, -60)
            ) {
                Card(
                    elevation = CardDefaults.cardElevation(4.dp),
                    modifier = Modifier.padding(8.dp)
                ) {
                    Text(currentTooltipContent, modifier = Modifier.padding(12.dp))
                }
            }
            */
        }
    }
}

4. 动态文本适配

当用户输入变化时,只需重新调用buildAnnotatedText生成新的AnnotatedString,传给TermTooltipText即可,Compose会自动重组更新:

@Composable
fun DynamicTextWithTooltips() {
    var userInput by remember { mutableStateOf("我正在学习Compose和Jetpack") }
    val termMap = remember {
        mapOf(
            "Compose" to "Jetpack Compose是Google推出的声明式UI框架,用于构建Android、iOS等多平台应用界面",
            "Jetpack" to "Jetpack是一系列Android库的集合,帮助开发者遵循最佳实践、减少样板代码"
        )
    }
    val annotatedText = remember(userInput) {
        buildAnnotatedText(userInput, termMap)
    }

    Column {
        TextField(value = userInput, onValueChange = { userInput = it })
        TermTooltipText(annotatedText = annotatedText)
    }
}

方案优势

  • 无需手动维护偏移量、长度等额外数据结构,注解与文本片段直接绑定,逻辑更简洁
  • 适配动态文本场景,输入变化时仅需重新构建AnnotatedString,自动触发组件更新
  • 注解可扩展,后续如需添加其他交互(如跳转),只需新增注解类型

内容的提问来源于stack exchange,提问作者Boofhead

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 18:07:36