Searching a List with Check Box Selection in Jetpack Compose

2k views Asked by At

Currently there is a Lazy Column with Text along with Custom Checkbox. I am currently able to maintain the Checkbox selection in Lazy Column by using the following code. Even during scrolls (up/down) it is able to maintain the state of Checkbox selection.

var baseCodes: MutableList<String> = arrayListOf()
val cmdList: List<MetaData> = mainViewModel.cmdList
val indexList: MutableList<Boolean> = MutableList(cmdList.size) { false }

LazyColumn() {
        itemsIndexed(cmdList) { index: Int, cmd ->
            MetaDataCard(
                cmd = cmd,
                navController = navController,
                mainViewModel = mainViewModel,
                indexList,
                index
            ) {
                if (it) {
                    baseCodes.add(cmd.code)
                } else {
                    baseCodes.remove(cmd.code)
                }
                categoryViewModel.baseCodes = baseCodes
            }
        }
    }

I have implemented the Search with Text with Below Logic.

 val cmdList: List<MetaData> = mainViewModel.cmdList
    val filteredList: List<MetaData>
    val searchText = textState.value.text

    filteredList = if (searchText.isEmpty()) {
        cmdList
    } else {
        val resultList = cmdList.filter { x ->
            x.name!!.contains(searchText, true) || x.code.contains(searchText, true)
        }
        resultList
    }

val indexList: MutableList<Boolean> = MutableList(filteredList.size) { false }
 LazyColumn() {
        itemsIndexed(filteredList) { index: Int, cmd ->
            MetaDataCard(
                cmd = cmd,
                navController = navController,
                mainViewModel = mainViewModel,
                indexList,
                index
            ) {
                if (it) {
                    baseCodes.add(cmd.code)
                } else {
                    baseCodes.remove(cmd.code)
                }
                categoryViewModel.baseCodes = baseCodes
            }
        }
    }


The Metadata Card is as below

fun MetaDataCard(
    cmd: MetaData,
    navController: NavController,
    mainViewModel: MainViewModel,
    completedList: MutableList<Boolean>,
    index: Int,
    processChange: (checked: Boolean) -> Unit
) {
    val isSelected = rememberSaveable { mutableStateOf(completedList[index]) }

    Card(
        modifier = Modifier
            .fillMaxWidth()
            .clip(RoundedCornerShape(8.dp)),
        elevation = 10.dp,
        backgroundColor = Color.White
    ) {
        Row(
            modifier = Modifier
                .fillMaxWidth()
                .padding(8.dp),
            verticalAlignment = Alignment.CenterVertically
        )
        {
           
            Column() {
                Text(
                    text = cmd.name,
                    color = Color.Gray,
                    style = Typography.body2
                )
                Text(
                    text = cmd.code,
                    Modifier.padding(0.dp),
                    color = MaterialTheme.colors.onPrimary,
                    style = Typography.body1,
                )
            }
            Spacer(modifier = Modifier.weight(0.8f))
            CustomCheckBox(
                checked = isSelected.value,
                onCheckedChange = {
                    isSelected.value = !isSelected.value
                    completedList[index] = !isSelected.value
                    processChange(isSelected.value)
                },
            )
        }
    }
}

Now with Search option, the list gets filtered as per the text in the Search box. However, now I am able to search and filter the text, but the checkbox selection is not retained and is messing up selection.

2

There are 2 answers

1
Narek Hayrapetyan On

Use

mutableStateListOf<Boolean>() as completedList

Change

val indexList: SnapshotStateList<Boolean> = mutableStateListOf()

Or you can simply convert any list to mutable state list

myList.toMutableStateList()
0
jjsan On

I've used your code and this is what I modified to make it work: to Row Im sending list of selected MetaData and in Row im setting isSelected if the shown Metadata is in selected Metadatas. it works also for searching and scrolling

i have it modified for employees fun Row( employee: EmployeeIdAndNameDTO, selectedEmployees: List, processChange: (checked: Boolean) -> Unit ) { var isSelected = selectedEmployees.contains(employee) ...