Reputation: 27
I have a Grid with two columns and 6 elements, but I need that the user select only 3 elements
In the first @Composable I put the value in this way:
LazyVerticalGrid(
columns = GridCells.Fixed(2),
) {
items(list.values.size) {
InterestsItems(
value = list.values[it].text,
)
}
}
And the second @Composable(InterestsItems) is a Box with an Image inside. I put the value like this:
var isSelected by remember { mutableStateOf(false) }
Box(modifier = Modifier.noRippleClickable { isSelected = !isSelected })
The result is that I select all the elements, is not what I want.
Upvotes: 1
Views: 1632
Reputation: 67159
You can create a data class to hold selected flag for any item
data class InterestsItem(val text: String, val isSelected: Boolean = false)
A ViewModel that keeps items and indexes of selected items and function to toggle between selected and not selected
class InterestsViewModel : ViewModel() {
val interestItems = mutableStateListOf<InterestsItem>()
.apply {
repeat(6) {
add(InterestsItem(text = "Item$it"))
}
}
private val selectedItems = mutableListOf<Int>()
fun toggleSelection(index: Int) {
val item = interestItems[index]
val isSelected = item.isSelected
if (isSelected) {
interestItems[index] = item.copy(isSelected = false)
selectedItems.remove(index)
} else if (selectedItems.size < 3) {
interestItems[index] = item.copy(isSelected = true)
selectedItems.add(index)
}
}
}
MutableStateListOf
will trigger recomposition when we change item
@Composable
private fun SelectItemsFromGridSample(interestsViewModel: InterestsViewModel) {
LazyVerticalGrid(
columns = GridCells.Fixed(2),
contentPadding = PaddingValues(8.dp),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
itemsIndexed(interestsViewModel.interestItems) { index, item ->
InterestsItemCard(interestsItem = item) {
interestsViewModel.toggleSelection(index)
}
}
}
}
And some Composable with callback to pass that item is clicked
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun InterestsItemCard(interestsItem: InterestsItem, onClick: () -> Unit) {
ElevatedCard(
modifier = Modifier.size(100.dp),
onClick = onClick
) {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = interestsItem.text, fontSize = 30.sp)
if (interestsItem.isSelected) {
Icon(
modifier = Modifier
.size(50.dp)
.background(Color.Green, CircleShape),
imageVector = Icons.Default.Check,
tint = Color.White,
contentDescription = null
)
}
}
}
}
Result
Upvotes: 2
Reputation: 6863
You are apparently using a common isSelected
variable for all the items. If you use a loop to render the items, move the variable declaration inside the loop.
Take the basic programming codelabs on the Android Developers Official Website, to walk through the basics. A strong base in general programming is foundational to learning about any specific programming paradigms/fields. Definitely take the Compose Pathway, now renamed to the Jetpack Compose Course, before anything. In this scenario, you'll need to create either a list representing the selected items, or a hash-map, which is basically a list in which each element is a pair of two objects. When the size of the list/map gets to 3, handle the event inside the on-click, to prevent further selection. That'll depend on what you want to do, and should be custom to your project.
Upvotes: 1
Reputation: 1473
Put the isSelected
variable inside the items block.
Example;
val list = remember { mutableStateOf(listOf("0","1","2","3","4","5") )}
LazyVerticalGrid(
columns = GridCells.Fixed(2),
) {
items(list.value.size){
var isSelected by remember { mutableStateOf(false) }
Text(
modifier = Modifier.clickable{
isSelected = !isSelected
},
text = list.value[it],
color = if (isSelected) Color.Red else Color.Black
)
}
}
Result;
Upvotes: 0