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

Android笔记应用文本格式化问题:选中加粗后取消选中样式消失

问题描述

我想给我的Android笔记应用实现文本格式化功能,选中文本后可以设置加粗、斜体等样式。我用下面的代码实现加粗功能:

var annotatedString = remember { mutableStateOf(AnnotatedString("")) }

var textFieldValue =
    remember { mutableStateOf<TextFieldValue>(TextFieldValue(annotatedString.value)) }

fun makeTextBold(textFieldValue: MutableState<TextFieldValue>) {
    val selection = textFieldValue.value.selection
    if (!selection.collapsed) {
        val annotatedString = buildAnnotatedString {
            append(textFieldValue.value.annotatedString.subSequence(0, selection.start))
            
            withStyle(style = SpanStyle(fontWeight = FontWeight.Bold)) {
                append(
                    textFieldValue.value.annotatedString.subSequence(
                        selection.start,
                        selection.end
                    )
                )
            }

            append(
                textFieldValue.value.annotatedString.subSequence(
                    selection.end,
                    textFieldValue.value.annotatedString.length
                )
            )
        }

        textFieldValue.value = textFieldValue.value.copy(annotatedString)
    }
}

// 然后在TextField中使用textFieldValue
TextField(
    value = textFieldValue.value,
    onValueChange = { textFieldValue.value = it },
    modifier = Modifier
        .fillMaxWidth()
        .padding(16.dp),
)

但现在代码有问题:只有文本处于选中状态时加粗样式才生效,取消选中后文本就恢复正常,不再显示加粗效果。请问我哪里错了?


问题原因与修复方案

错误原因

你当前的代码只在makeTextBold方法里临时构建了带样式的AnnotatedString,但没有同步更新你定义的annotatedString核心状态变量。同时,TextField默认的onValueChange回调会用输入的纯文本覆盖textFieldValue里的样式信息——因为默认逻辑会把用户输入转换成无样式的AnnotatedString,导致之前设置的加粗样式直接丢失。

修复步骤

  1. 同步更新核心状态:在makeTextBold中,不仅要更新textFieldValue,还要同步更新annotatedString,确保样式信息被持久化存储。
  2. 自定义onValueChange逻辑:在TextField的回调里,不要直接覆盖状态,而是基于原有的annotatedString保留已有的样式,只更新文本内容。

修改后的完整代码示例:

@Composable
fun NoteEditor() {
    // 核心状态:持久化保存带样式的文本
    val annotatedString = remember { mutableStateOf(AnnotatedString("")) }
    // TextField状态,基于核心annotatedString初始化
    val textFieldValue = remember {
        mutableStateOf(TextFieldValue(annotatedString.value))
    }

    fun makeTextBold() {
        val selection = textFieldValue.value.selection
        if (!selection.collapsed) {
            val newAnnotatedString = buildAnnotatedString {
                // 追加选中区域之前的文本
                append(annotatedString.value.subSequence(0, selection.start))
                // 给选中区域添加加粗样式
                withStyle(SpanStyle(fontWeight = FontWeight.Bold)) {
                    append(annotatedString.value.subSequence(selection.start, selection.end))
                }
                // 追加选中区域之后的文本
                append(annotatedString.value.subSequence(selection.end, annotatedString.value.length))
            }
            // 同步更新两个状态变量
            annotatedString.value = newAnnotatedString
            textFieldValue.value = textFieldValue.value.copy(annotatedString = newAnnotatedString)
        }
    }

    Column(modifier = Modifier.padding(16.dp)) {
        // 加粗触发按钮
        Button(onClick = { makeTextBold() }) {
            Text("加粗")
        }

        TextField(
            value = textFieldValue.value,
            onValueChange = { newValue ->
                // 自定义更新逻辑:保留原有样式,同步文本内容
                val updatedAnnotatedString = buildAnnotatedString {
                    append(newValue.text)
                    // 复制原有所有样式到新文本
                    annotatedString.value.getSpanStyles(0, annotatedString.value.length)
                        .forEach { spanStyle ->
                            addStyle(spanStyle.item, spanStyle.start, spanStyle.end)
                        }
                    // 若有字符串注解也需同步(比如链接等)
                    annotatedString.value.getStringAnnotations(0, annotatedString.value.length)
                        .forEach { annotation ->
                            addStringAnnotation(annotation.tag, annotation.item, annotation.start, annotation.end)
                        }
                }
                // 更新核心状态
                annotatedString.value = updatedAnnotatedString
                textFieldValue.value = newValue.copy(annotatedString = updatedAnnotatedString)
            },
            modifier = Modifier
                .fillMaxWidth()
                .padding(top = 16.dp)
                .height(200.dp),
            textStyle = TextStyle(fontSize = 16.sp)
        )
    }
}

额外说明

  • 如果要支持斜体、下划线等其他样式,只需在对应的格式化方法中替换SpanStyle的参数(比如fontStyle = FontStyle.Italic、textDecoration = TextDecoration.Underline)即可。
  • 若要处理重复样式(比如同一文本多次点击加粗),可以先判断选中区域是否已存在对应样式,避免重复叠加。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 16:48:11