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

Jetpack Compose Text如何实现类似Telegram的包裹子串批量加粗功能

Jetpack Compose 自定义Text实现**包裹内容加粗效果

原实现问题

  • 正则使用贪心匹配.*,会匹配从第一个**到最后一个**之间的所有内容,无法正确拆分多组独立的加粗片段
  • 仅调用一次find()只能获取第一个匹配结果,不支持多组加粗片段渲染
  • 全局替换所有**字符,会误删不合法、不成对的标记,不符合测试用例要求
  • 加粗样式的位置基于原始字符串计算,全局删除**后字符串长度变短,导致样式位置错位

修正方案

  1. 调整正则规则,匹配成对**包裹、且中间无连续*的非空内容,避免匹配非法格式
  2. 遍历所有合法匹配结果,直接在构建AnnotatedString的过程中分段处理普通文本和加粗文本,不需要提前修改原字符串,避免位置偏移问题
  3. 不合法、不成对的**标记会原样保留,不做任何处理

完整实现代码

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp

// 加粗匹配正则:匹配成对**包裹、中间无连续*的非空内容
private val boldRegex = Regex("\\*\\*([^*]*(?:\\*[^*]+)*)\\*\\*")

@Composable
fun CustomText(text: String, modifier: Modifier = Modifier) {
    val annotatedString = buildAnnotatedString {
        var currentProcessPos = 0
        // 查找所有合法匹配
        val allMatches = boldRegex.findAll(text)

        allMatches.forEach { matchResult ->
            // 取出加粗内容,空内容直接跳过
            val boldContent = matchResult.groupValues[1].takeIf { it.isNotEmpty() } ?: return@forEach
            // 追加当前匹配之前的普通文本
            append(text.substring(currentProcessPos, matchResult.range.first))
            // 追加带加粗样式的内容
            withStyle(
                style = SpanStyle(
                    fontWeight = FontWeight.Bold,
                    color = Color(0xff64B5F6),
                    fontSize = 15.sp
                )
            ) {
                append(boldContent)
            }
            // 更新处理位置到当前匹配的结束下标
            currentProcessPos = matchResult.range.last + 1
        }
        // 追加最后一段剩余的普通文本
        append(text.substring(currentProcessPos))
    }

    Text(
        modifier = modifier
            .fillMaxWidth()
            .padding(horizontal = 8.dp, vertical = 12.dp),
        fontSize = 16.sp,
        text = annotatedString
    )
}

效果验证

上述实现完全符合你给出的4条测试用例预期:

  1. 单组成对**包裹的内容正常加粗,标记被移除
  2. 多组成对**包裹的内容分别加粗,标记被移除,剩余单个*原样保留
  3. 非法格式的**组合无匹配,所有内容原样保留,无样式修改
  4. 无闭合的**标记无匹配,所有内容原样保留,无样式修改

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 02:09:02