How to trigger ripple effect on Switch click for its container

Viewed 154

I want to replicate the effect used in the Settings app for Android 12, where the ripple effect is automatically triggered whenever an option is clicked (including the Switch itself). However, in my app, the ripple effect does not happen at all, only the Switch animates.

@Composable
fun ComposableSettingSimpleMode() {
    val isChecked = remember { mutableStateOf(false) }

    Row(modifier = Modifier
        .fillMaxWidth()
        .clickable(onClick = {})) {
        Text(text = stringResource(id = R.string.simple_mode))
        Switch(checked = isChecked.value, onCheckedChange = {
            isChecked.value = it
        })
    }
}
2 Answers

You can use the toggleable modifier:

@Composable
fun ComposableSettingSimpleMode() {
    val isChecked = remember { mutableStateOf(false) }

    Row(
        modifier = Modifier
            .fillMaxWidth()
            .toggleable(
                value = isChecked.value,
                onValueChange = { isChecked.value = it },
            ),
    ) {
        Text(text = "Hello")
        Switch(checked = isChecked.value, onCheckedChange = null)
    }
}

The important points are:

  • The entire row is made "toggleable" (i.e. whatever you want to have the ripple effect on);
  • The toggleable modifier requires a value, which should have the same value as the switch, and an onValueChange, which should perform the actual switch state change (which currently is on the Switch's onCheckedChange);
  • The Switch's onCheckedChange should be set to null, otherwise it will "steal" the click from the row when the Switch is clicked, and the row won't ripple;

This is where you pass in your own InteractionSource

    var isChecked by remember { mutableStateOf(false) }
    val interactionSource = remember { MutableInteractionSource() }
    Row(
        modifier = Modifier
            .fillMaxWidth()
            .clickable(
                interactionSource = interactionSource,
                indication = LocalIndication.current,
                onClick = {
                    isChecked = !isChecked
                }
            )
    ) {
        Text(text = "Dummy Text", Modifier.weight(1f))
        Switch(
            checked = isChecked,
            interactionSource = interactionSource,
            onCheckedChange = {
                isChecked = it
            })
    }
Related