Jetpack Compose文本框撤销重做系统开发问题求助
Jetpack Compose 文本框撤销/重做功能修复
问题1:定时器重置失效修复
- 问题核心:之前的定时器未在用户输入时正确取消旧任务,导致旧延迟任务仍会触发记录逻辑。
- 修复方式:使用协程
Job管理延迟任务,每次输入时先取消当前的延迟Job,再启动新的延迟任务,确保只有用户停止输入达到设定时长后,才会触发历史记录。
问题2:合并短时间内输入记录
- 问题核心:每输入一个字符就直接添加历史,未做批次合并。
- 修复方式:仅在延迟任务触发时更新历史记录;同时,当用户在非最新历史位置输入时,清除后续的重做历史,保证撤销/重做逻辑的一致性。
修改后的核心代码(ViewModel层)
import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.delay import kotlinx.coroutines.launch class EditorViewModel : ViewModel() { var text by mutableStateOf("") private set private val history = mutableListOf("") var currentIndex by mutableIntStateOf(0) private set private var delayJob: Job? = null // 可根据需求调整延迟时长,比如1000ms即停止输入1秒后记录 private val DEBOUNCE_DELAY = 1000L fun onTextChanged(newText: String) { text = newText // 重置定时器:取消旧任务,启动新延迟 delayJob?.cancel() delayJob = CoroutineScope(Dispatchers.Main).launch { delay(DEBOUNCE_DELAY) updateHistory() } } private fun updateHistory() { if (text == history[currentIndex]) return // 如果当前不是最新历史,清除后续重做记录 if (currentIndex < history.size - 1) { history.subList(currentIndex + 1, history.size).clear() } history.add(text) currentIndex = history.size - 1 } fun undo() { if (currentIndex > 0) { currentIndex-- text = history[currentIndex] delayJob?.cancel() } } fun redo() { if (currentIndex < history.size - 1) { currentIndex++ text = history[currentIndex] delayJob?.cancel() } } }
Compose界面调用示例
@Composable fun EditorScreen(viewModel: EditorViewModel = viewModel()) { Column(modifier = Modifier.padding(16.dp)) { TextField( value = viewModel.text, onValueChange = viewModel::onTextChanged, modifier = Modifier.fillMaxWidth().weight(1f), placeholder = { Text("输入内容...") } ) Row( modifier = Modifier.fillMaxWidth().padding(top = 8.dp), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Button( onClick = viewModel::undo, enabled = viewModel.currentIndex > 0, modifier = Modifier.padding(end = 16.dp) ) { Text("撤销") } Button( onClick = viewModel::redo, enabled = viewModel.currentIndex < viewModel.history.size - 1 ) { Text("重做") } } } }
关键逻辑说明
- 定时器重置:每次输入时通过
delayJob?.cancel()终止旧的延迟任务,再启动新任务,确保只有停止输入后才会记录历史。 - 批次合并:延迟触发时才将当前文本加入历史,短时间内连续输入会被合并为一条记录。
- 历史一致性:当用户在已撤销的历史位置输入新内容时,清除后续的重做记录,避免出现逻辑混乱。
内容的提问来源于stack exchange,提问作者Bob Rasner
相关产品推荐
相关产品推荐

