从列表中删除项目会导致 LazyColumn 中显示错误

Mik*_*elT 5 android kotlin android-jetpack-compose lazycolumn compose-recomposition

我认为这是一个奇怪的情况。Textfields我正在显示a 中的列表LazyColoumn。用户可以删除每个文本字段,但这样做时,它会复制 REPLACE 文本字段中的值。

移除前

移除后

发生了什么:

我添加了 3 个人:第 1 人、第 2 人、第 3 人

我单击“删除人员 2”。

人员 3 现在位于人员 2 的位置(参见名称),但复制了人员 2 的 VALUE。

我这样管理状态:

private val peopleStateFlow = MutableStateFlow<List<Person>>()
Run Code Online (Sandbox Code Playgroud)

我像这样加载该列:

val peopleState = viewModel.peopleState.collectAsState()
LazyColumn {
    val peopleStateSnap = peopleState.value
    items(peopleStateSnap.size) { index ->
    val person = peopleStateSnap[index]
    ParticipantView(
        person = person,
        sharedOwed = sharedOwed.value,
        onChangeListener = {
            viewModel.updateOwed(person, it)
        },
        onRemoveClicked = {
            viewModel.removePerson(person)
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

我这样删除这个人:

fun removePerson(person: Person) {
        val indexOf = peopleState.value.indexOf(person)
        val updateList = peopleState.value.toMutableList()
        updateList.removeAt(indexOf)
        peopleStateFlow.value = updateList
    }
Run Code Online (Sandbox Code Playgroud)

我什至尝试在删除之前和之后记录此列表

21:22:05.468  I  qqq oldList=[1.0, 2.0, 0.0]
21:22:05.468  I  qqq removed = 2.0
21:22:05.468  I  qqq updateList=[1.0, 0.0]
Run Code Online (Sandbox Code Playgroud)

而且它似乎已被正确删除,因此问题 100% 在于重构,或者 Compose 如何管理 LazyColumn 或 Textfield 的状态。

z.g*_*g.y 4

我无法编译您的代码,尽管我怀疑它与类似,您LazyColumn只是根据其索引位置来识别项目的位置,而不是其提供的数据结构中唯一的东西。

并根据官方文档

默认情况下,每个项目的状态都根据该项目在列表或网格中的位置进行设置。但是,如果数据集发生更改,这可能会导致问题,因为更改位置的项目实际上会丢失任何记住的状态。如果您想象一下 LazyColumn 中的 LazyRow 场景,如果该行更改了项目位置,则用户将丢失该行中的滚动位置。

因此,我假设您的Person属性中有一些独特的东西,您可以将其key作为LazyColumn's item.

items(peopleStateSnap.size, key = { < something unique to person here > } ) { index ->
   ...
}
Run Code Online (Sandbox Code Playgroud)

更新

keysLazy item您的数据没有唯一/稳定并且情况阻止您修改其结构时,似乎还有另一种不使用唯一/稳定的方法。

您可以将item's可组合项包装在 a 中,movableContentOf{...}以便在更改时跟踪它们的状态Lazy,如下所示

LazyColumn {
    
    items(peopleStateSnap.size) { index ->
        val person = peopleStateSnap[index]

        val movableContent = movableContentOf {
            ParticipantView(
                person = person,
                sharedOwed = sharedOwed.value,
                onChangeListener = {
                    viewModel.updateOwed(person, it)
                },
                onRemoveClicked = {
                    viewModel.removePerson(person)
                })
        }

        movableContent()
    }
}
Run Code Online (Sandbox Code Playgroud)