Search code examples
androidandroid-jetpack-composehighlightlazycolumn

Highlight only one Card in Compose through selection


i have a Compose LazyColumnList which shows the content (from a List) in single cards. I want to highlight the selected card only. Now when i select another card, the first card stays highlighted. Here is the code:

...
LazyColumn(
               contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
    ) {
        items(
            items = sql_quran,
            itemContent = { SurahListItem(quran_einzeln = it, navController)
            })
    }


@Composable
fun SurahListItem(
    quran_einzeln: ItemData_quran,
    navController: NavController,
) {

var selectedCard by remember { mutableStateOf(false) }
var cardColor = if (selectedCard) Blue else White;

// var cardColor= if (selectedCard) LightGray else White
Card(
    modifier = Modifier.padding(horizontal = 8.dp, vertical = 8.dp).fillMaxWidth().fillMaxSize(),
    elevation = 2.dp,
    shape = RoundedCornerShape(corner = CornerSize(16.dp)),
    backgroundColor = cardColor,
    onClick = {
        selectedCard=!selectedCard
    }

)

Solution

  • All state changes are happening locally within your SurahListItem and nothing tells your LazyColumn to perform any updates to its item children every time you click one of them.

    I can't compile your entire code, so I just assumed some parts of it resulting to the codes below. I hoisted the "selection state" that you want one level above from your SurahListItem and have the composable that contains the LazyColumn do the updates.

    You can copy-and-paste all of these in a single .kt file and you'll be able to run it separately from some root composable screen/content.

    data class ItemData_quran(val content: String)
    
    @Composable
    fun MyCards( sql_quran: List<ItemData_quran>) {
    
        var selectedItem by remember {
            mutableStateOf<ItemData_quran?>(null)
        }
    
        LazyColumn(
            contentPadding = PaddingValues(horizontal = 16.dp, vertical = 8.dp)
        ) {
            items(
                items = sql_quran,
                itemContent = { surah ->
                    SurahListItem(
                        quran_einzeln = surah,
                        setSelected = selectedItem?.let {
                            surah.content == it.content
                        } ?: false
                    ) {
                        selectedItem = it
                    }
                }
            )
        }
    }
    
    @OptIn(ExperimentalMaterialApi::class)
    @Composable
    fun SurahListItem(
        quran_einzeln: ItemData_quran,
        setSelected: Boolean,
        isSelected: (ItemData_quran?) -> Unit
    ) {
    
        val cardColor = if (setSelected) Blue else White
    
        Card(
            modifier = Modifier
                .padding(horizontal = 8.dp, vertical = 8.dp)
                .wrapContentSize(),
            elevation = 2.dp,
            shape = RoundedCornerShape(corner = CornerSize(16.dp)),
            backgroundColor = cardColor,
            onClick = {
                isSelected(if(!setSelected) quran_einzeln else null)
            }
        ) {
            Box(
                modifier = Modifier.fillMaxWidth(),
                contentAlignment = Alignment.Center
            ) {
                Text(text  = quran_einzeln.content)
            }
        }
    }
    

    Usage:

    MyCards(
        listOf(
                ItemData_quran("Item 1"),
                ItemData_quran("Item 2"),
                ItemData_quran("Item 3"),
                ItemData_quran("Item 4"),
                ItemData_quran("Item 5"),
                ItemData_quran("Item 6"),
                ItemData_quran("Item 7"),
              )
    )
    

    enter image description here