Jetpack Compose LazyColumn - 如何分别更新每个项目的值?

2024-01-02

我正在为我的应用程序开发购物车功能。我希望分别添加/减少 LazyColumn 中每个列表项的数量。我只使用一个“记住”,因此如果我单击添加/减少,它们都会同时更新。如何单独控制每个项目?

截屏 https://i.stack.imgur.com/Dgd7V.png

@Composable
fun InventoryCartScreen(
    mainViewModel: MainViewModel = hiltViewModel()
) {

    val multiSelectValue = mutableStateOf(0)// This is the value I want to change

//random list
val shopList = listOf(
        ShoppingList(id = 0,itemNumber = "1",itemDescription = "1",currentInventory = 0,optimalInventory = 0,minInventory = 0),
        ShoppingList(id = 0,itemNumber = "2",itemDescription = "2",currentInventory = 0,optimalInventory = 0,minInventory = 0)
    )

    Column(...) {
       LazyColumn(...) {
            items(items = shopList, key = { it.id }) { item ->
                InventoryCartScreenContents(
                    onaddClick= { multiSelectValue.value ++ }, //adds for all
                    onDecreaseClick = { multiSelectValue.value -- }, //decreases for all
                    value = multiSelectValue.value //setting the initial value for all
                )

            }

        }
    }
}

以下是可帮助您重现问题的可组合内容。

@Composable
fun InventoryCartScreenContents(
    onAddClick: (Int) -> Unit,
    onDecreaseClick: () -> Unit,
    value: Int,
) {
           Row(...) {
                Button(
                    onClick = { onAddClick(itemId) }
                ) {
                    Text(text = "+")
                }
               
                Button(
                    onClick = onDecreaseClick
                ) {
                    Text(text = "-")
                }
               
                }

            }


创建一个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多变的。现在,我们的ComposeButtonComposable 确实读取了以下值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)),你应该很好地完成这件事......最后。如果您还有任何疑问,请尽管询问。如果没有任何效果,我可以通过视频通话提供帮助。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Jetpack Compose LazyColumn - 如何分别更新每个项目的值? 的相关文章

随机推荐

  • SQLAlchemy 关系加载器在表上留下锁?

    我有非常简单的代码导致我的 MySQL 数据库挂起 import sqlalchemy as sa from sqlalchemy import orm creating the engine the base etc import uti
  • 如何在 Jetty 中部署 Servlet?

    我创建了一个简单的 Servlet 我想将其部署在 Jetty 7 2 中 Jetty 正在运行并且能够为 JSP 页面提供服务http localhost 8080 jonas test jsp 我用 Jetty 启动java jar s
  • React 18 TypeScript 儿童 FC

    我升级到 React 18 并且编译得很好 如今 似乎每个使用子组件的组件都会抛出错误 Property children does not exist on type IPageProps 在儿童道具自动包含在之前FC界面 现在看来我必须
  • 将 IN 子句与 PIG FILTER 结合使用

    PIG 支持 IN 子句吗 filtered FILTER bba BY reason not in a b c d 或者我应该把它分成多个 OR Thanks 您可以使用 Apache DataFu 中的以下 udf 代替 这将帮助您避免
  • 如何在 JPA 2.0 项目中加载 Hibernate 'xxx.hbm.cfg' 文件?

    我刚刚启动了一个 Spring Roo 应用程序 使用 Hibernate 作为 JPA2 0 提供程序 我使用罐 子的方式如下 hibernate core 3 6 4 Final jar hibernate commons annota
  • 使用 C# 中的架构进行 XML 解析

    我正在编写一些在运行时加载 xml 文件的代码 目前 我们使用 XmlDocument 类型来读取 xml 文件 并在 SelectSingleNode 语句周围包装一个 try catch 这是在节点为 null 或在我们解析用户时不存在
  • iOS 从后台重新检查加载位置

    我正在构建一个应用程序 它根据您当前的位置显示结果数据 目前 我正在使用viewDidLoad的方法UIViewController开始CLLocationManager并获取当前位置 一旦我获得了与我想要的准确性相匹配的位置 我就会向我的
  • 从发布的 JSON 获取经典 ASP 变量

    我正在尝试通过 AJAX 将 JSON 发布到经典 ASP 页面 该页面检索值 检查数据库并将 JSON 返回到原始页面 我可以通过 AJAX 发布 JSON 我可以从 ASP 返回 JSON 我无法将发布的 JSON 检索到 ASP 变量
  • 在 Golang 中导入 C 错误:cc1.exe:错误:给出的文件名太多

    我正在尝试导入并使用 C 包 但我不断收到此错误 runtime cgo cc1 exe error too many filenames given Type cc1 exe help for usage cc1 exe fatal er
  • 将域指向我的远程 Node JS 应用程序?

    我正在尝试弄清楚如何在我的 Ubuntu 10 04 LTS 服务器上准确部署 Node JS 我读过许多不同的博客和文章 它们解释了多种不同的方式 大多数似乎已经过时了 或者看起来并没有真正发挥作用 看来最简单的解决办法就是使用Forev
  • 部分类文件的命名约定

    我正在生成大部分 ASP NET MVC 脚手架代码 所有生成的文件都是使用标准命名约定的部分类 例如 我的员工控制器文件名为 EmployeeController cs 如果我希望使用自定义的非生成逻辑扩展 EmployeeControl
  • Visual Studio 2019:起始页而不是起始窗口

    Visual Studio引入了阻塞Start Window而不是非阻塞Start Page 考虑到Visual Studio的可扩展性如何 有没有办法让VS2019显示非阻塞Start Page The new Start Window非
  • switch 语句:“期望一个常量值”

    目前我正在与 神奇的字符串 问题作斗争 public class MyDataField class definition exuecuted method public void SwitchMultipleDataFields var
  • 如何将三个sql选择组合成一个查询

    我有下面的三个查询 我想将它们合并为一个查询 这样我就可以得到三列 其中包含按县划分的结果 我尝试对所有表进行内部联接 但得到的数据很差 如何组合这三个查询并按县分组 select Total DLL Children SUM cd Num
  • java中通过反射设置对象字段的值

    首先 我有一个这样的对象 public class Entity public int data1 public String data2 public float data3 public SubEntity data4 public c
  • 如何将字节转换为字符串?

    我需要转换我的Byte to a String because NSInteger write const uint8 t buffer maxLength NSUInteger takes a String作为它的第一个参数 我想要的是
  • 需要 root 才能在运行时通过应用程序执行 shell 命令“输入 keyevent <#>”?

    我正在尝试执行 adb shell 命令input keyevent 5在运行时通过我的应用程序接听电话 如果我这样做 Runtime getRuntime exec input keyevent 5 它似乎没有执行 什么也没有发生 但是当
  • 如何在 Azure DevOps 中从 .vdproj 构建安装项目?

    我最近将一些 Windows 应用程序升级到 VS2019 并使用 VS2019 中的 VSInstallerProject 扩展创建了安装项目 我注意到 运行发布管道时 安装程 序并未创建 但我需要此处的 msi 或 exe 文件 以便我
  • Gradle 无法解析来自神器的依赖关系

    我正在尝试构建一个 android library MyLib1 它依赖于 gradle 和 jenkins 中的另一个 android library MyLib2 我有点绝望 因为我认为我的 gradle 文件和设置都没有问题 我成功地
  • Jetpack Compose LazyColumn - 如何分别更新每个项目的值?

    我正在为我的应用程序开发购物车功能 我希望分别添加 减少 LazyColumn 中每个列表项的数量 我只使用一个 记住 因此如果我单击添加 减少 它们都会同时更新 如何单独控制每个项目 截屏 https i stack imgur com