Android Jetpack Compose:如何计算移动端单行文本的单词数量
在Jetpack Compose中计算Text组件每行的单词数量
Jetpack Compose的Text组件本身没有直接暴露每行文本的详细信息,要计算每行的单词数,需要借助自定义Layout获取文本的布局测量数据,再结合原始文本的单词列表进行匹配统计。
实现步骤与代码示例
1. 单词分割工具函数
先实现一个函数,把原始文本分割成单词列表,处理连续空格的情况:
fun splitIntoWords(text: String): List<String> { // 按任意数量的空白字符分割,过滤空字符串 return text.split(Regex("\\s+")).filter { it.isNotEmpty() } }
2. 自定义Layout组件获取每行信息
创建一个自定义Layout包裹Text,通过Placeable的API获取每行的字符起止索引,再匹配对应的单词:
@Composable fun WordCountText( text: String, modifier: Modifier = Modifier, style: TextStyle = TextStyle.Default, // 回调返回每行的单词数列表 onLineWordCounts: (List<Int>) -> Unit ) { // 缓存分割后的单词和每个单词的起始索引 val words = remember(text) { splitIntoWords(text) } val wordStartIndices = remember(words) { val indices = mutableListOf<Int>() var currentPos = 0 words.forEachIndexed { index, word -> indices.add(currentPos) // 单词间加空格的长度(最后一个单词不加) currentPos += word.length + if (index < words.lastIndex) 1 else 0 } indices } Layout( content = { Text(text = text, style = style) }, modifier = modifier ) { measurables, constraints -> val textPlaceable = measurables.first().measure(constraints) layout(textPlaceable.width, textPlaceable.height) { textPlaceable.place(0, 0) val lineWordCounts = mutableListOf<Int>() val totalLines = textPlaceable.lineCount for (lineIndex in 0 until totalLines) { val lineStart = textPlaceable.getLineStart(lineIndex) // visibleEnd=true 获取实际显示的行尾(排除省略号截断的内容) val lineEnd = textPlaceable.getLineEnd(lineIndex, visibleEnd = true) var wordCount = 0 // 遍历每个单词,判断是否与当前行有重叠 wordStartIndices.forEachIndexed { wordIndex, wordStart -> val wordEnd = if (wordIndex < words.lastIndex) { wordStartIndices[wordIndex + 1] - 1 } else { text.length - 1 } // 单词的范围与行范围有交集,就算作该行的单词 if (!(wordEnd < lineStart || wordStart > lineEnd)) { wordCount++ } } lineWordCounts.add(wordCount) } // 返回统计结果 onLineWordCounts(lineWordCounts) } } }
3. 使用示例
在界面中调用自定义组件,获取并展示每行的单词数:
@Composable fun DemoScreen() { val longText = "Jetpack Compose is a modern toolkit for building native Android UI. It simplifies and accelerates UI development on Android with less code, powerful tools, and intuitive Kotlin APIs. You can use it to build beautiful, responsive UIs quickly and efficiently." var lineWordCounts by remember { mutableStateOf<List<Int>>(emptyList()) } Column(modifier = Modifier.padding(16.dp)) { WordCountText( text = longText, style = TextStyle(fontSize = 16.sp), modifier = Modifier.fillMaxWidth(), onLineWordCounts = { counts -> lineWordCounts = counts } ) Spacer(modifier = Modifier.height(16.dp)) Text("每行单词统计:") lineWordCounts.forEachIndexed { index, count -> Text("第${index + 1}行:$count 个单词") } } }
注意事项
- 上述实现以空白字符作为单词分隔符,如果需要支持标点符号(比如逗号、句号后的分割),可以修改
splitIntoWords的正则表达式,例如Regex("[\\s.,!?]+") - 如果
Text使用了maxLines或overflow = TextOverflow.Ellipsis,getLineEnd的visibleEnd=true会确保只统计实际显示的内容 - 统计逻辑基于单词与行的范围交集,一个单词跨两行时会被计入两行的单词数,如果你需要调整这种情况的统计规则,可以修改判断条件
内容的提问来源于stack exchange,提问作者Mohammad Hanif Shaikh
相关产品推荐
相关产品推荐

