android-jetpack-composeandroid-checkboxandroid-jetpack-compose-lazy-column

CheckBox State is not changing in jetpack compose LazyColumn items()


 val areAllChecked = rememberSaveable {
                mutableStateOf(false)
            }
            MyApplicationTheme {
                LazyColumn(modifier = Modifier.fillMaxSize()) {
                    item {
                        IconButton(onClick = { areAllChecked.value = false }) {
                            Icon(imageVector = Icons.Default.Clear, contentDescription = null)
                        }
                    }
                    item {
                        Row(verticalAlignment = Alignment.CenterVertically){
                            Text(text = "Parent")
                            Checkbox(checked = areAllChecked.value, onCheckedChange = {
                                areAllChecked.value = it
                            })
                        }
                    }
                    items(5) {
                        val isChecked = rememberSaveable(areAllChecked.value) {
                            mutableStateOf(areAllChecked.value)
                        }
                        Row(verticalAlignment = Alignment.CenterVertically){
                            Text(text = it.toString())
                            Checkbox(checked = isChecked.value, onCheckedChange = {
                                isChecked.value = it
                            })
                        }
                    }
                }
            }

How can i fix this?

Thank you.


Solution

  • You need to wrap your item into the Data Class to manage the state of each item easily.

    Here is the full example

    Why use LaunchedEffect because we don't want to load it every time. We want to change only when the CheckBox of Parent changes.

    Whenever changes are made in the single item we loop through and change its value and assign a new list to current.

    import androidx.compose.foundation.layout.Column
    import androidx.compose.foundation.layout.Row
    import androidx.compose.foundation.layout.fillMaxSize
    import androidx.compose.foundation.layout.padding
    import androidx.compose.foundation.lazy.LazyColumn
    import androidx.compose.foundation.lazy.items
    import androidx.compose.material.icons.Icons
    import androidx.compose.material.icons.filled.Clear
    import androidx.compose.material3.Checkbox
    import androidx.compose.material3.ExperimentalMaterial3Api
    import androidx.compose.material3.Icon
    import androidx.compose.material3.IconButton
    import androidx.compose.material3.Scaffold
    import androidx.compose.material3.Text
    import androidx.compose.material3.TopAppBar
    import androidx.compose.runtime.Composable
    import androidx.compose.runtime.LaunchedEffect
    import androidx.compose.runtime.getValue
    import androidx.compose.runtime.mutableStateOf
    import androidx.compose.runtime.remember
    import androidx.compose.runtime.saveable.rememberSaveable
    import androidx.compose.runtime.setValue
    import androidx.compose.ui.Alignment
    import androidx.compose.ui.Modifier
    
    
    data class CheckedItem(
        val text: String, val isSelected: Boolean = false
    )
    
    @OptIn(ExperimentalMaterial3Api::class)
    @Composable
    fun Stack021(modifier: Modifier = Modifier) {
    
        val list = listOf(
            CheckedItem("A", false),
            CheckedItem("B", false),
            CheckedItem("C", false),
            CheckedItem("D", false),
            CheckedItem("E", false),
            CheckedItem("F", false),
            CheckedItem("G", false)
        )
    
        var useList by remember {
            mutableStateOf(list)
        }
    
    
        val isAllAreCheck = rememberSaveable {
            mutableStateOf(false)
        }
        
        LaunchedEffect(isAllAreCheck.value) {
            useList = if (isAllAreCheck.value) {
                useList.mapIndexed { j, item ->
                    item.copy(isSelected = true)
                }
            } else {
                useList.mapIndexed { j, item ->
                    item.copy(isSelected = false)
                }
            }
        }
    
        Scaffold(topBar = {
            TopAppBar(title = {
                Text(text = "Multi Select Demo")
            })
        }) { padding ->
    
    
            Column(
                modifier = Modifier
                    .padding(padding)
                    .fillMaxSize()
            ) {
    
                IconButton(onClick = {
                    println("All Are Unchecked")
                    useList = useList.mapIndexed { j, item ->
                        item.copy(isSelected = false)
                    }
                }) {
                    Icon(imageVector = Icons.Default.Clear, contentDescription = null)
                }
    
                Row(verticalAlignment = Alignment.CenterVertically) {
                    Text(text = "Parent")
                    Checkbox(
                        checked = isAllAreCheck.value,
                        onCheckedChange = {
                            isAllAreCheck.value = it
                        }
                    )
                }
    
    
                LazyColumn(
                    modifier = Modifier
                        .fillMaxSize()
                        .weight(1f)
                ) {
                    items(useList.size) { i ->
    
                        Row(verticalAlignment = Alignment.CenterVertically) {
                            Text(text = useList[i].text)
                            Checkbox(checked = useList[i].isSelected, onCheckedChange = {
                                useList = useList.mapIndexed { j, item ->
                                    if (i == j) {
                                        item.copy(isSelected = it)
                                    } else item
                                }
                            })
                        }
    
                    }
                }
            }
    
        }
    }