Home > other >  Change background color of surface item when click in jetpack compose
Change background color of surface item when click in jetpack compose

Time:11-25

I want to make a background color change when user select a item on Surface. I am using Column in my parent, so I can't make LazyColumn. So I am using Foreach to make a list of view. By default no view will be selected, when user click on item then I want change the color. Note: Only one item will select at a time.

ScanDeviceList

@Composable
fun ColumnScope.ScanDeviceList(
    scanDeviceList: List<ScanResult>,
    modifier: Modifier = Modifier,
    pairSelectedDevice: () -> Unit
) {
    Spacer()
    AnimatedVisibility() {
        Column {
            Text()
            Spacer()
            scanDeviceList.forEachIndexed { index, scanResult ->
                ClickableItemContainer(
                    rippleColor = AquaLightOpacity10,
                    content = {
                        ScanDeviceItem(index, scanResult, scanDeviceList)
                    }
                ){}
            }
            AvailableWarningText()
            PairSelectedDevice(pairSelectedDevice)
        }
    }
}

ScanDeviceItem

@Composable
fun ScanDeviceItem(
    index: Int,
    scanResult: ScanResult,
    scanDeviceList: List<ScanResult>
) {
    Column {
        if (index == 0) {
            Divider(color = Cloudy, thickness = 1.dp)
        }
        Text(
            text = scanResult.device.name,
            modifier = Modifier.padding(vertical = 10.dp)
        )
        if (index <= scanDeviceList.lastIndex) {
            Divider(color = Cloudy, thickness = 1.dp)
        }
    }
}

ClickableItemContainer

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun ClickableItemContainer(
    rippleColor: Color = TealLight,
    content: @Composable (MutableInteractionSource) -> Unit,
    clickAction: () -> Unit
) {
    val interactionSource = remember { MutableInteractionSource() }
    CompositionLocalProvider(
        LocalRippleTheme provides AbcRippleTheme(rippleColor),
        content = {
            Surface(
                onClick = { clickAction() },
                interactionSource = interactionSource,
                color = White
            ) {
                content(interactionSource)
            }
        }
    )
}

I want to something like this

enter image description here

Now above solution is only working on ripple effect, Now I want to extend my function to select a single item at a time. Many Thanks

CodePudding user response:

You can store the selected index and use the clickAction to update its value when the user clicks on each item.

Something like:

@Composable
fun MyList(

      var selectedIndex by remember { mutableStateOf(-1) }

      Column() {
          itemsList.forEachIndexed() { index, item ->
              MyItem(
                  selected = selectedIndex == index,
                  clickAction = { selectedIndex = index }
              )
      }
}

@Composable
fun MyItem(
    selected : Boolean = false,
    clickAction: () -> Unit
){
     Surface(
        onClick = { clickAction() },
        color = if (selected) Color.Red else Color.Yellow
     ) {
         Text("Item...")
     }
}

CodePudding user response:

To have only item selected at a time, you can follow a behavior that is similar. You save your item selected in a mutableState variable, like:

var itemSelected by remember { mutableState(ScanDeviceResult()) }

After that, when you click the item, you update the itemSelected, something like:

ClickableItemContainer(
                    rippleColor = AquaLightOpacity10,
                    content = {
                        ScanDeviceItem(index, scanResult, scanDeviceList)
                    }
                ){ newItemSelected ->
itemSelected = newItemSelected
}

Now, each ClickableItemContainer needs to have an associated ScanResult.

    @OptIn(ExperimentalMaterialApi::class)
@Composable
fun ClickableItemContainer(
itemSelected: ScanResult,
scanResult: ScanResult,
    rippleColor: Color = TealLight,
    content: @Composable (MutableInteractionSource) -> Unit,
    clickAction: (ScanResult) -> Unit
) {
    val interactionSource = remember { MutableInteractionSource() }
    CompositionLocalProvider(
        LocalRippleTheme provides AbcRippleTheme(rippleColor),
        content = {
            Surface(
                onClick = { clickAction.invoke(scanResult) },
                interactionSource = interactionSource,
                color = if (itemSelected == scanResult) YOUR_BACKGROUND-SELECTED_COLOR else White
            ) {
                content(interactionSource)
            }
        }
    )
}

Now, on your ScanDeviceList method:

    @Composable
    fun ColumnScope.ScanDeviceList(
        itemSelected: MutableState<ScanResult>,
        scanDeviceList: List<ScanResult>,
        modifier: Modifier = Modifier,
        pairSelectedDevice: () -> Unit
    ) {
        Spacer()
        AnimatedVisibility() {
            Column {
                Text()
                Spacer()
                scanDeviceList.forEachIndexed { index, scanResult ->
                    ClickableItemContainer(
                        itemSelected = itemSelected,
                        scanResult = scanResult,
                        rippleColor = AquaLightOpacity10,
                        content = {
                            ScanDeviceItem(index, scanResult, scanDeviceList)
                        }
                    ){ scanResultToSelect ->
               itemSelected = scanResultToSelect
}
                }
                AvailableWarningText()
                PairSelectedDevice(pairSelectedDevice)
            }
        }
    }
  • Related