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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 21:27:03