7

PROBLEM ::: I want to create a lazy column where I can select or deselect only one option at a time. Right now, whenever I click on row component inside lazy column, all the rows get selected.

CODE :::

@Composable fun LazyColumnWithSelection() { var isSelected by remember { mutableStateOf(false) } var selectedIndex by remember { mutableStateOf(0) } val onItemClick = { index: Int -> selectedIndex = index } LazyColumn( modifier = Modifier.fillMaxSize(), ) { items(100) { index -> Row(modifier = Modifier .fillMaxWidth() .clickable { onItemClick.invoke(index) if (selectedIndex == index) { isSelected = !isSelected } } .padding(16.dp), horizontalArrangement = Arrangement.SpaceBetween, verticalAlignment = Alignment.CenterVertically) { Text(text = "Item $index", modifier = Modifier.padding(12.dp), color = Color.White) if (isSelected) { Icon(imageVector = Icons.Default.Check, contentDescription = "Selected", tint = Color.Green, modifier = Modifier.size(20.dp)) } } } } } 

CURRENT RESULT :::

Before Clicking ->

Before Clicking

After Clicking ->

After Clicking

You can see all the items are getting selected but I should be able to select or deselect one item at a time not all.

I tried to use remember state for selection but I think I'm doing wrong something in the index selection or maybe if statement.

3
  • Thats because you are checking the "isSelected" value in order to display / hide the icon. I think it should be if (selectedIndex == index) instead of if (isSelected). Do you need "isSelected" at all? Commented Nov 2, 2022 at 22:11
  • @F.G. if i do if (selectedIndex == index) , it going to set index 0 as default option and also there will be no option to de-select the selected row component . That's why I have to use if(isSelected). But you are also right i have to use if (selectedIndex == index) outside the clickable to get the updated selectedIndex value. Commented Nov 2, 2022 at 23:47
  • Please check this post stackoverflow.com/questions/74151392/… Commented Nov 3, 2022 at 0:42

2 Answers 2

8

This should probably give you a head start.

So we have 4 components here:

  • Data Class
  • Class state holder
  • Item Composable
  • ItemList Composable

ItemData

 data class ItemData( val id : Int, val display: String, val isSelected: Boolean = false ) 

State holder

class ItemDataState { val itemDataList = mutableStateListOf( ItemData(1, "Item 1"), ItemData(2, "Item 2"), ItemData(3, "Item 3"), ItemData(4, "Item 4"), ItemData(5, "Item 5") ) // were updating the entire list in a single pass using its iterator fun onItemSelected(selectedItemData: ItemData) { val iterator = itemDataList.listIterator() while (iterator.hasNext()) { val listItem = iterator.next() iterator.set( if (listItem.id == selectedItemData.id) { selectedItemData } else { listItem.copy(isSelected = false) } ) } } } 

Item Composable

@Composable fun ItemDisplay( itemData: ItemData, onCheckChanged: (ItemData) -> Unit ) { Row( modifier = Modifier .fillMaxWidth() .height(80.dp) .border(BorderStroke(Dp.Hairline, Color.Gray)), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween ) { Text(text = if (itemData.isSelected) "I'm selected!" else itemData.display) Checkbox( checked = itemData.isSelected, onCheckedChange = { onCheckChanged(itemData.copy(isSelected = !itemData.isSelected)) } ) } } 

Finally the ItemList (LazyColumn)

@Composable fun ItemList() { val itemDataState = remember { ItemDataState() } LazyColumn { items(itemDataState.itemDataList, key = { it.id } ) { item -> ItemDisplay( itemData = item, onCheckChanged = itemDataState::onItemSelected ) } } } 

All of these are copy-and-pasteable so you can run it quickly. The codes should be simple enough for you to dissect them easily and use them as a reference for your own use-case.

Notice that we use a data class here which has an id property to be unique and we're using it as a key parameter for LazyColumn's item.

I usually implement my UI collection components with a unique identifier to save me from potential headaches such as UI showing/removing/recycling wrong items.

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

thank you so much for this briefed anwser. I modified the code a bit and able to select and de-select the component but issue is now it is performing as multi-selection.
i think i have to update the hide/show state in the viewModel iteself
0

Remember index instead of Boolean (isSelected).

1 Comment

with remember index i think i will not be able to hide the icon.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.