I have a list of items where each has a checkbox. The state of the checkbox needs to be stored in the viewmodel
and preferable the list in the viewmodel
should be the only source of truth.
@Composable
fun Screen(viewModel: ViewModel) {
val list by viewModel.items.observeAsState()
LazyColumn {
list?.let { items ->
items(items) { item ->
ListItem(
text = {
Text(item.name)
},
secondaryText = {
Text(item.phoneNumber)
},
icon = {
Checkbox(
modifier = Modifier.padding(8.dp),
checked = item.selected,
onCheckedChange = {
//TODO
}
)
}
)
}
}
}
}
I have tried to update the item.selected
by updating the list (MutableLiveData<List<Object>>
in viewmodel
) in the onCheckedChange
callback, but the UI does not update. If i scroll down and then up the UI updates and the checkbox appears to be checked. Why does it not update?
MutableLiveData
knows nothing about the object it holds. It cannot send you new value when some inner object property is updated.
To solve this with live data, you need to set new value to you items, setting the same value will be enough:
fun setSelected(index: Int, selected: Boolean) {
items.value!![index].selected = selected
items.value = items.value
}
But if you're not bind to LiveData
by other dependencies, I suggest you not using it. Using mutableStateListOf
with immutable data class
is much cleaner:
data class Object(val selected: Boolean)
class VM: ViewModel() {
val items = mutableStateListOf<Object>()
fun setSelected(index: Int, selected: Boolean) {
items[index] = items[index].copy(selected = selected)
}
}
In both cases, you need the object index, you can get it with itemsIndexed
:
val list = viewModel.items
LazyColumn {
itemsIndexed(list) { index, item ->
// ...
onCheckedChange = {
viewModel.setSelected(index, it)
}
// ...
}
}