android - 如何在可组合功能中一次只打开一个编辑表单
问题描述
我在 LazyColumn 中显示了一个包含一个单词的行列表。单击该行时,将打开一个编辑表单。数据来自房间数据库。
由于该行位于单独的可组合函数上,因此我可以一起打开许多不同的编辑表单(每行一个)。但我想一次只在整个列表中显示一个编辑表单。如果我单击一行打开编辑表单,则应关闭其他行上的其余打开表单。我怎样才能做到这一点?
这是代码:
val words: List<Word> by wordViewModel.allWords.observeAsState(listOf())
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,
onSaveUpdatedWord = { onUpdateWord(it) },
onTrashClicked = { onDeleteWord(it) }
)
}
}
@Composable
fun WordItemLayout(word: Word, onSaveUpdatedWord: (Word) -> Unit, onTrashClicked: (Word) -> Unit) {
var showEditForm by remember { mutableStateOf(false) }
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 {
showEditForm = !showEditForm
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)
)
// Delete Button
IconButton(
onClick = {
showEditForm = false
onTrashClicked(word)
Toast.makeText(context, "Word deleted", Toast.LENGTH_SHORT).show()
},
modifier = Modifier.size(12.dp)
) {
Icon(
imageVector = Icons.Filled.Delete,
contentDescription = "Delete Word",
tint = Color.White
)
}
}
// word edit form
if (showEditForm) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.Bottom
) {
TextField(
value = editedWord,
onValueChange = { editedWord = it },
modifier = Modifier.weight(1f),
colors = TextFieldDefaults.textFieldColors(backgroundColor = Color.White) // TextField Background Color
)
// Update Button
Button(
onClick = {
val updatedWord: Word = word
if (updatedWord.word != editedWord.trim()) {
updatedWord.word = editedWord.trim()
onSaveUpdatedWord(updatedWord)
Toast.makeText(context, "Word updated", Toast.LENGTH_SHORT).show()
}
showEditForm = false
},
modifier = Modifier.padding(start = 8.dp)
) {
Icon(imageVector = Icons.Filled.Done, contentDescription = "Update Word")
}
}
}
}
}
谢谢你的帮助!
解决方案
一种方法:在您的视图模型中,声明一个openRowIndex
状态(这将存储打开行的索引,例如,您可以将其初始化为 -1)。定义一个可以改变这个状态的方法,例如updateOpenRowIndex
我不确定您在视图模型中使用的是哪种状态持有者。我将StateFlow
用于这个答案。在您的视图模型中声明新的状态和方法:
private val _openRowIndex = MutableStateFlow(-1)
val openRowIndex: StateFlow<Int> = _openRowIndex
fun updateOpenRowIndex(updatedIndex: Int) {
_openRowIndex.value = updatedIndex
}
对于可兼容的每一行,将index
其传入LazyColumn
. itemsIndexed
您可以使用该方法获取索引。还要收集你的openRowIndex
,并将其传递给可组合的。还传入更新打开行索引的方法:
itemsIndexed(words) { index, word ->
//get the current opened row state and collect it (might look different for you if you are not using StateFlow):
val openRowIndex = wordViewModel.openRowIndex.collectAsState()
WordItemLayout(
word = word,
onSaveUpdatedWord = { onUpdateWord(it) },
onTrashClicked = { onDeleteWord(it) },
index = index, //new parameter!
openRowIndex = openRowIndex.value //new parameter!
onUpdateOpenedRow = wordViewModel::updateOpenRowIndex //new parameter!
)
}
现在,在可组合的行中,只需检查index
and是否openRowIndex
匹配,仅当它们匹配时才显示打开的行。现在更新打开的行:使Row
可点击,并在点击时使用视图模型updateOpenRowIndex
方法将状态更新为index
. 当状态随着新打开的行发生变化时,Compose 将处理其余部分并重新组合!
fun WordItemLayout(
word: Word,
onSaveUpdatedWord: (Word) -> Unit,
onTrashClicked: (Word), -> Unit,
index: Int, //new parameters
openRowIndex: Int,
onUpdateOpenedRow: (Int) -> Unit
) {
if(index == openRowIndex) {
//display this row as opened
} else {
//display this row as closed
}
}
正如我所说,使该行可点击并调用更新函数:
Row(
modifier = Modifier.clickable {
onUpdateOpenedRow(index)
//additional instructions for what to happen when row is clicked...
}
//additional row parameters...
)
推荐阅读
- python-3.x - 我在使用此代码时遇到了计算问题
- python - Windows 安装程序必须写入注册表(使用 NSIS 安装的已编译 python 应用程序)
- node.js - Azure 管道中的 UI 测试显示错误找不到使用节点 js 的 chrome 二进制文件
- android - Admob 在 Android 应用程序中导致 NullPointerException
- javascript - 从父组件访问子组件引用
- processing - 转换为字符串的整数不能按预期工作
- django - 使用页码重定向回列表视图
- gf - 在 GF 中生成所有属格
- node.js - 为新手解释异步等待代码块。为什么 user.password_hash 为空?
- kubernetes - 在部署 Kubernetes 资源时更改 Pulumi 的超时时间