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

如何在Android Jetpack Compose(Kotlin)中实现词典APP逐词点击跳转功能?

在Jetpack Compose中实现长文本单词点击跳转功能

不需要为每个单词单独创建Text组件,利用Compose的AnnotatedString配合ClickableText就能高效实现长文本内单词的点击跳转,以下是具体实现步骤:

1. 构建带点击标记的AnnotatedString

先实现一个工具函数,将普通文本拆分为单词,并为每个单词添加可点击的注解,注解中存储单词本身以便后续获取:

fun createClickableTextAnnotatedString(text: String): AnnotatedString {
    // 按空格+常见标点拆分单词,可根据需求调整正则规则
    val words = text.split(Regex("[\\s,.!?;:]+"))
    val builder = AnnotatedString.Builder()
    
    words.forEachIndexed { index, word ->
        if (word.isBlank()) return@forEachIndexed
        
        // 添加单词文本
        builder.append(word)
        // 添加单词间的分隔符(保留原文本的标点/空格)
        val nextSeparator = text.substringAfter(word).takeWhile { it in " ,.!?;:\t\n" }
        builder.append(nextSeparator)
        
        // 为当前单词添加点击注解,存储单词内容
        val startIndex = builder.length - word.length - nextSeparator.length
        val endIndex = builder.length - nextSeparator.length
        builder.addStringAnnotation(
            tag = "WORD",
            annotation = word,
            start = startIndex,
            end = endIndex
        )
    }
    return builder.toAnnotatedString()
}

2. 使用ClickableText渲染并处理点击事件

用ClickableText组件渲染构建好的AnnotatedString,并在点击时解析注解,获取点击的单词后跳转至释义页面:

@Composable
fun ClickableWordText(
    text: String,
    onWordClick: (String) -> Unit // 用回调处理跳转逻辑,解耦导航依赖
) {
    val annotatedString = createClickableTextAnnotatedString(text)
    
    ClickableText(
        text = annotatedString,
        style = TextStyle(fontSize = 16.sp),
        onClick = { offset ->
            annotatedString.getStringAnnotations(
                tag = "WORD",
                start = offset,
                end = offset
            ).firstOrNull()?.let { annotation ->
                onWordClick(annotation.item)
            }
        }
    )
}

3. 调用组件并实现跳转逻辑

在父组件中传入点击回调,处理跳转至释义页面的逻辑(以Navigation组件为例):

@Composable
fun DictionaryContent(navController: NavController) {
    val sampleText = "Hello world! This is a sample text for dictionary app."
    
    Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        ClickableWordText(text = sampleText) { clickedWord ->
            // 跳转到释义页面,传递单词参数
            navController.navigate("definition/$clickedWord")
        }
    }
}

4. 释义页面接收参数并展示内容

在释义页面中获取传递的单词,加载并展示对应的释义:

@Composable
fun DefinitionScreen(navController: NavController) {
    val word = navController.currentBackStackEntry?.arguments?.getString("word") ?: ""
    
    Column(
        modifier = Modifier.fillMaxSize().padding(16.dp),
        verticalArrangement = Arrangement.Top,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = word, style = TextStyle(fontSize = 22.sp, fontWeight = FontWeight.Bold))
        // 替换为实际的释义加载逻辑(本地数据库/API请求)
        Text(text = "此处展示「$word」的详细释义", style = TextStyle(fontSize = 16.sp, marginTop = 20.dp))
    }
}

优化细节

  • 可给点击单词添加样式区分:在构建AnnotatedString时,通过builder.addStyle()添加下划线或高亮色:
    builder.addStyle(
        style = SpanStyle(color = Color(0xFF2196F3), textDecoration = TextDecoration.Underline),
        start = startIndex,
        end = endIndex
    )
    
  • 若需要支持中文分词,需替换单词拆分逻辑,引入中文分词库(如HanLP)处理文本。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 22:55:17