So here's an odd one, I think. I'm showing a list of Textfields
in a LazyColoumn
. The user can remove each of the textfields, but when doing so, it copies the value from REPLACE textfield.
What's happening:
I have added 3 people: Person 1, Person 2, Person 3
I click remove Person 2.
Person 3 is now at Person 2's position (See the name), but copied Person 2' VALUE.
I manage the state like this:
private val peopleStateFlow = MutableStateFlow<List<Person>>()
I load the column like this:
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)
})
}
}
And I remove the person like this:
fun removePerson(person: Person) {
val indexOf = peopleState.value.indexOf(person)
val updateList = peopleState.value.toMutableList()
updateList.removeAt(indexOf)
peopleStateFlow.value = updateList
}
I even tried logging this list before and after the removal
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]
And it is seemingly being removed correctly, so the problem lies 100% with recompose, or how Compose manage a LazyColumn's or Textfield's state.
I can't compile your code, though I suspect its similar to this, your LazyColumn
is only identifying the position of the items based on its index position and not something unique from its supplied data structure.
And based on the official docs
By default, each item's state is keyed against the position of the item in the list or grid. However, this can cause issues if the data set changes, since items which change position effectively lose any remembered state. If you imagine the scenario of LazyRow within a LazyColumn, if the row changes item position, the user would then lose their scroll position within the row.
So I'd assume you have something unique in your Person
properties that you can supply as a key
to your LazyColumn's
item
.
items(peopleStateSnap.size, key = { < something unique to person here > } ) { index ->
...
}
Update:
There seems to be another way without using unique/stable keys
for a Lazy
item
when your data doesn't have one and if circumstances prevent you from modifying its structure.
You can wrap your item's
composable inside a movableContentOf{...}
so their states are being tracked on Lazy
changes, something like this
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()
}
}