【问题标题】:How to keep only one edit form open at a time in a composable function如何在可组合功能中一次只打开一个编辑表单
【发布时间】:2021-08-14 00:32:40
【问题描述】:

我在 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")
                }
            }
        }
    }
}

感谢您的帮助!

【问题讨论】:

    标签: android kotlin android-jetpack-compose


    【解决方案1】:

    一种方法:在您的视图模型中,声明一个openRowIndex 状态(这将存储打开行的索引,例如,您可以将其初始化为-1)。 定义一个可以改变这个状态的方法,例如updateOpenRowIndex

    我不确定您在视图模型中使用的是哪种状态持有者。我将使用StateFlow 来回答这个问题。在您的视图模型中声明新的状态和方法:

    private val _openRowIndex = MutableStateFlow(-1)
    val openRowIndex: StateFlow<Int> = _openRowIndex
    
    fun updateOpenRowIndex(updatedIndex: Int) {
       _openRowIndex.value = updatedIndex
    }
    

    对于可组合的每一行,在LazyColumn 中传递它的index。您可以使用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!
        )
    
    }
    

    现在,在可组合的行中,只需检查 indexopenRowIndex 是否匹配,仅当它们匹配时才显示打开的行。现在更新打开的行:使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...
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-05
      • 1970-01-01
      • 2017-11-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多