创建一个mutableStateListOf(...)
(or mutableStateOf(listOf(...))
对象(如果前者不支持您的数据类型)ViewModel
。现在,从您想要读取它的可组合项访问此状态,即您的LazyColumn
.
在你的里面ViewModel
,您可以根据需要设置这些值,并且它们将在更新时在可组合项中更新。现在,可组合项(即您的列)可以使用列表项的索引作为惰性列项的索引。因此,您可以在视图模型中为不同的项目存储不同的数据,并且它会正常工作。
问题似乎是您在这里缺少状态提升的概念。我以为我有一些很好的帖子解释它,但似乎this https://stackoverflow.com/a/69675205/15880865一个是我发布过的最好的。无论如何,我建议检查这个官方参考 https://developer.android.com/codelabs/jetpack-compose-state#8,因为这就是我基本上发现的地方(可以说,有一点猎头。)
基本思想是所有内容都存储在 viewModel 中。然后,将该状态分为“setter”和“getters”,并将它们沿层次结构传递。
例如,ViewModel 可能有一个名为text
, ok?
class VM : ViewModel(){
var text by mutableStateOf("Initial Text")
private set // This ensures that it cannot be directly modified by any class other than the viewmodel
fun setText(newText: Dtring){ // Setter
text = newText
}
}
如果您想更新的值text
单击按钮时,这就是您将该按钮与 viewModel 连接起来的方式
MainActivity{
onCreate{
setContent{
StateButton(
getter = viewModel.text, // To get the value
setter = viewModel::setText // Passing the setter directly
)
}
}
}
在您的 Button Composable 声明中
@Composable
private fun ComposeButton(
getter: String,
setter: (String) -> Unit // (receive 'String') -> return 'Unit' or 'void'
){
Button(
onClick = { setter("Updated Text") } // Calls the setter with value "Updated Text", updating the value in the viewModel
){
Text(text = getter)
}
}
该按钮从 viewModel 读取值“get”,即读取text
,因为它将模型传递给可组合项。然后,当我们收到来自按钮的点击事件时(在onClick
),我们调用作为 Composable 参数接收到的 setter,并使用新值调用它,在本例中为“Updated Text”,这将一直向上到达 viewModel,并更改text
在那里。
Now, text
最初被初始化为国家持有者,通过使用mutableStateOf(...)
在初始化时,它的值改变时会触发重组。现在,由于值实际上确实发生了变化(从“初始文本”到“更新文本”),因此将在读取该值的所有可组合项上触发重组。text
多变的。现在,我们的ComposeButton
Composable 确实读取了以下值text
,因为我们直接将它传递给getter
该 Composable 的参数,对吗?因此,所有这些都将产生一个可组合项,它将从层次结构(视图模型)中的单个点读取值,并且仅在该值更改时更新。因此,Viewmodel 充当可组合项的单一事实来源。
运行此命令时,您将得到一个可组合项,该可组合项最初显示为“初始文本”,但当您单击它时,它会更改为“更新的文本”。我们在 getter 和 setter 的帮助下将可组合项连接到主 viewModel。当可组合项接收事件时,我们调用从模型接收的 setter,这些 setter 将链继续向上至 viewModel,并更改模型内变量(状态持有者)的值。然后,可组合项已经通过“getters”读取这些变量,因此,它们重新组合以反映更新的值。这就是状态提升。所有状态都存储在 viewModel 中,并传递给可组合项。当值需要更改时,可组合项将“事件”向上传递到 viewModel(沿层次结构向上),然后在更新值时,更新后的状态将向下传递到可组合项(“状态”沿层次结构向下流动) 。
您所需要的只是使用此方法,但带有一个列表。您可以使用项目的索引来跟踪项目,并在 viewModel 中更新它们的属性,如本示例演示的更新值a
。您可以将项目的所有属性存储在单个列表中。
只需创建一个数据类,就像这样
data class Item(p1: ..., p2:..., p3 : ...){}
Then, val list by mutableStateOf(listOf<Item>())
Clear?
好的,这是针对您的用例的具体解释。
您的代码似乎太大了,但这是我得到的:
惰性列中有两个项目,每个项目都有三个按钮。你的问题是关于两个按钮,增加和减少。您希望按钮仅修改它们所属项目的属性,对吧?
好吧,再次使用状态提升,如上所述
ViewModel{
val list by mutableStateOf(listOf<Item>()) // Main (central) list
val updateItem(itemIndex: Int, item: Item){
list.set(itemIndex, item) // sets the element at 'itemIndex' to 'item'
} // You can fill the list with initial values if you like, for testing
}
创建 Getter 和 Setter 后,您将使用它们来读取和更新整个项目,即使您必须修改它们的单个属性。我们可以使用方便的方法,例如copy()
让我们在这里的生活更轻松。
MainScreen(){
//Assuming here is the LazyColumn
list = viewModel.list // Get the central list here
LazyColumn(...){ // Try to minimize code like this in your questions, since it does not have to compile, just an illustration.
items(list){ item ->
// Ditch the multiSelectValue, we have the state in the model now.
Item( // A Composable, like you demonstrated, but with a simpler name for convenience
item: Item,
onItemUpdate: (Item) -> Unit // You don't need anything else
)
}
}
}
只需创建一个数据类并将所有内容存储在其中即可。班上Item
(不是可组合的)我演示的是数据类。它可能有这样的值
data class Item(var quantity: Int, ...){} // We will increase/decrease this
现在,在你的Item
可组合,您可以在其中接收“添加”事件(在onClick
的“添加”按钮),只需使用设置器更新值,如下所示
onClick = {
updateItem(
item // Getter
.copy( //Convenience Method
quantity = item.quantity + 1 // Increase current Quantity
)
)
}
只需对减少和删除执行相同的操作(updateItem(0)
),你应该很好地完成这件事......最后。如果您还有任何疑问,请尽管询问。如果没有任何效果,我可以通过视频通话提供帮助。