如何在Composable函数中实现同一时间仅打开一个编辑表单
实现思路
核心是状态提升:你现在每个WordItemLayout自己持有编辑表单的开关状态,组件之间互相独立,自然可以同时打开多个。只要把「当前正在编辑的条目ID」这个共享状态提到LazyColumn所在的父层统一管理,就能实现全局只有一个编辑表单打开的效果。
具体修改步骤
1. 修改父层代码
在LazyColumn所在的父Composable中新增全局编辑状态,统一控制哪个条目可以打开编辑表单:
val words: List<Word> by wordViewModel.allWords.observeAsState(listOf()) // 新增:记录当前正在编辑的单词ID,为null表示没有条目处于编辑状态,假设你的Word实体类主键字段为id,类型为Int var editingWordId by remember { mutableStateOf<Int?>(null) } var newWord by remember { mutableStateOf("") } val context = LocalContext.current val keyboardController = LocalSoftwareKeyboardController.current LazyColumn( modifier = Modifier .weight(1f) .padding(vertical = 16.dp), verticalArrangement = Arrangement.spacedBy(4.dp) ) { items(words) { word -> WordItemLayout( word = word, // 传入当前条目是否处于编辑状态:当前编辑ID等于条目ID时为true isEditing = editingWordId == word.id, // 点击条目时更新全局编辑ID onToggleEdit = { targetIsOpen -> editingWordId = if (targetIsOpen) word.id else null }, onSaveUpdatedWord = { updatedWord -> onUpdateWord(updatedWord) // 保存后关闭编辑状态 editingWordId = null }, onTrashClicked = { deletedWord -> onDeleteWord(deletedWord) // 删除后关闭编辑状态 editingWordId = null } ) } }
2. 修改WordItemLayout子组件代码
移除内部的编辑开关状态,改用父层传入的参数控制:
@Composable fun WordItemLayout( word: Word, isEditing: Boolean, // 新增:父层传入的编辑状态 onToggleEdit: (Boolean) -> Unit, // 新增:通知父层切换编辑状态的回调 onSaveUpdatedWord: (Word) -> Unit, onTrashClicked: (Word) -> Unit ) { var editedWord by remember { mutableStateOf(word.word) } val context = LocalContext.current Column { Row( modifier = Modifier .fillMaxWidth() .background(MaterialTheme.colors.primaryVariant) .padding(vertical = 12.dp, horizontal = 24.dp) .clickable { // 不再自己控制开关,通知父层切换 val newState = !isEditing onToggleEdit(newState) editedWord = word.word }, verticalAlignment = Alignment.CenterVertically, ) { Image(painter = painterResource(R.drawable.ic_star), contentDescription = null) Text( text = word.word, color = Color.White, fontSize = 20.sp, modifier = Modifier .padding(start = 16.dp) .weight(1f) ) // 删除按钮 IconButton( onClick = { onTrashClicked(word) Toast.makeText(context, "Word deleted", Toast.LENGTH_SHORT).show() }, modifier = Modifier.size(12.dp) ) { Icon( imageVector = Icons.Filled.Delete, contentDescription = "删除单词", tint = Color.White ) } } // 单词编辑表单:改用父层传入的isEditing控制显示 if (isEditing) { Row( modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.Bottom ) { TextField( value = editedWord, onValueChange = { editedWord = it }, modifier = Modifier.weight(1f), colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White) ) // 更新按钮 Button( onClick = { val updatedWord: Word = word if (updatedWord.word != editedWord.trim()) { updatedWord.word = editedWord.trim() onSaveUpdatedWord(updatedWord) Toast.makeText(context, "单词已更新", Toast.LENGTH_SHORT).show() } }, modifier = Modifier.padding(start = 8.dp) ) { Icon(imageVector = Icons.Filled.Done, contentDescription = "更新单词") } } } } }
说明
如果你的Word实体类主键不是Int类型,只要把editingWordId的类型改成对应主键类型即可,逻辑完全不变。这样每次点击新的条目打开编辑时,全局的editingWordId会更新为新条目的ID,之前打开的条目会因为isEditing变成false自动关闭编辑表单,就实现了全局唯一打开的效果。
内容的提问来源于stack exchange,提问作者Raw Hasan
相关产品推荐
相关产品推荐

