Reputation: 95
Say I have a list of items in a LazyColumn
and they can all be selected. How can I make sure when an item is selected, the others are deselected (so only 1 item can be selected at once)?
I was thinking about interactionSource
but I'm not really sure how use it.
Upvotes: 1
Views: 2018
Reputation: 6863
Just store a variable holding the index of the selected variable
var sel by mutableStateOf(0)
Now you may want to use remember here if you are declaring it in your Composables, but I would highly recommend storing it inside a viewmodel. A simple example would be
class VM: ViewModel(){
var sel by mutableStateOf(0) //Assuming 0 is selected initially, change it to -1 if you please
//Create a setter optionally, for state-hoisting
fun setSel(index: Int){
sel = index
}
}
In the MainActivity,
class MainActivity{
val vm by viewmodels<VM>()
setContent{
MySelectableList(
list = ...,
selected = vm.sel,
onSelectionChange = vm::setSel // Just pass the viewmodel if you did not create the setter
)
}
@Composable
fun MySelectableList(
list: List<Any>,
selected: Int,
onSelectionChange: (int) -> Unit // or vm, if you did not create the setter
){
list.forEachIndexed {index, item ->
// Now create this Composable yourself
ItemComposable(
isSelected = index == selected,
onClick = { onSelectionChange(index) } // Just focus and have a look at what's happening here
)
}
}
}
I am using state-hoisting here, read this for reference. Def take this codelab if you haven't already
You will need to do an additional check if you set the initial value of sel to -1 earlier. Completely understand the code that is flowing through here.
Upvotes: 2
Reputation: 1929
You can try use remember {...}
@Composable
fun MyComposeList(data: List<MyItemData>,...) {
val (selectedItem, setSelectedItem) = remember { mutableStateOf(null // or maybe data.first() } // remember current selected by state delegate
lazyColumn() { // your lazy column
items (data) { item -> // item = each item
// your compose item view
MyComposeItemView (
data = item, // pass data by each item
isSelected = data == selectedItem // set is item selected by default
) {
// on item click
setSelectedItem(it)
}
}
}
}
@Composable
fun MyComposeItemView(
data: MyItemData,
isSelected: Boolean,
onSelect: (MyItemData) -> Unit = {}) {
// here set item selected state = isSelected maybe change color or something
// assume we have box as single item
Box(Modifier.clickable {
onSelect(data) // cal on click function and pass current data as parameter
})
}
Upvotes: 1
Reputation: 7670
I'd extract this logic into a ViewModel
, with your items being a specific UIModel that contains your current data of the items + their state, containing the isSelected
state.
For ex:
data class YourUiModel(val id: Long, val isSelected: Boolean = false, ...)
private val _items = MutableStateFlow(emptyList<YourUiModel>())
val items: StateFlow<List<YourUiModel>>
get() = _items
private fun changeSelectionTo(uiModel: YourUiModel) {
_items.value = items.value.map { it.copy(isSelected = it.id == uiModel.id) }
}
...
Upvotes: 3