user19846644
user19846644

Reputation: 27

How can I select only 3 element in a grid/list (jetpack compose)?

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

Answers (3)

Thracian
Thracian

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

enter image description here

Upvotes: 2

Richard Onslow Roper
Richard Onslow Roper

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

commandiron
commandiron

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;

enter image description here

Upvotes: 0

Related Questions