Create Toggle Button Group in Jetpack Compose without Radio Buttons

7.6k Views Asked by At

I am trying to put a button toggle group in my project that behaves similarly to a radio button group, but does not look like a radio button group (ie when one button is selected, the others are deselected).

I followed a radio button pattern I found online, but that doesn't seem to be doing the trick. Is there a way to do this? I've gotten to a point where I have the buttons in the place I want them, but they're both disabled.

MovieSpotterTheme() {
                Card(
                    modifier = Modifier
                        .fillMaxWidth()
                ) {
                    @Composable
                    fun MaterialButtonToggleGroup() {
                        var selected by remember { mutableStateOf("Android") }

                        val buttonGroup = listOf("Popular Movies", "Search Movies")

                     
                        val onSelectedChange = { text: String ->
                            selected = text
                        }
                        Row(
                            horizontalArrangement = Arrangement.SpaceEvenly
                        ) {
                            buttonGroup.forEach { text ->
                                Row(Modifier
                                    .selectable(
                                        selected = (text == selected),
                                        onClick = { onSelectedChange(text) }
                                    )
                                    .padding(horizontal = 16.dp)
                                ) {
                                    Button(
                                        enabled = (text == selected),
                                        onClick = { onSelectedChange(text) }
                                    ) {
                                        Column(
                                            horizontalAlignment = Alignment.CenterHorizontally
                                        ) {
                                            Text(
                                                text = text,
                                                style = MaterialTheme.typography.body1.merge(),
                                                modifier = Modifier.padding(horizontal = 16.dp)
                                            )
                                        }
                                    }
                                }
                            }
                        }
                    }
                    Surface() {
                        MaterialButtonToggleGroup()
                    }
                }
            }
2

There are 2 best solutions below

1
Abhimanyu On BEST ANSWER

Providing a simplified version. Play around with it to suit your requirement.

@Composable
fun CustomRadioGroup() {
    val options = listOf(
        "Option 1",
        "Option 2",
        "Option 3",
        "Option 4",
    )
    var selectedOption by remember {
        mutableStateOf("")
    }
    val onSelectionChange = { text: String ->
        selectedOption = text
    }

    Column(
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally,
        modifier = Modifier.fillMaxSize(),
    ) {
        options.forEach { text ->
            Row(
                modifier = Modifier
                    .padding(
                        all = 8.dp,
                    ),
            ) {
                Text(
                    text = text,
                    style = typography.body1.merge(),
                    color = Color.White,
                    modifier = Modifier
                        .clip(
                            shape = RoundedCornerShape(
                                size = 12.dp,
                            ),
                        )
                        .clickable {
                            onSelectionChange(text)
                        }
                        .background(
                            if (text == selectedOption) {
                                Color.Magenta
                            } else {
                                Color.LightGray
                            }
                        )
                        .padding(
                            vertical = 12.dp,
                            horizontal = 16.dp,
                        ),
                )
            }
        }
    }
}

Radio Group

0
AllanRibas On

In my case I had to do it like this

@Composable
fun ToggleList() {
    val musicList = listOf(
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
        Musics("Test song "),
    )

    val playing: SnapshotStateList<Boolean> = mutableStateListOf()

    musicList.onEachIndexed { index, _ ->
        playing.add(index, false)
    }

    val onSelectionChange = { index: Int, playerState: Boolean ->
        musicList.onEachIndexed { i, _ ->
            playing[i] = false
        }
        playing[index] = playerState
    }

    LazyColumn(
        content = {
            itemsIndexed(items = musicList) { index, item ->
                Card(
                    shape = RoundedCornerShape(10.dp),
                    elevation = CardDefaults.cardElevation(4.dp),
                    colors = CardDefaults.cardColors(MaterialTheme.colorScheme.background),
                    border = BorderStroke(4.dp, MaterialTheme.colorScheme.secondaryContainer),
                ) {
                    Text(
                        text = item.musicName.plus(index),
                        modifier = Modifier
                            .fillMaxWidth()
                            .padding(16.dp)
                    )
                    Icon(
                        modifier = Modifier
                            .clickable {
                                if (playing[index].not()) {
                                    onSelectionChange(index, true)
                                } else {
                                    onSelectionChange(index, false)
                                }
                            }
                            .size(70.dp)
                            .padding(10.dp)
                            .align(Alignment.End),
                        painter = if (playing[index]) {
                            painterResource(id = android.R.drawable.ic_media_pause)
                        } else {
                            painterResource(id = android.R.drawable.ic_media_play)
                        },
                        contentDescription = "play|pause songs",
                        tint = MaterialTheme.colorScheme.onBackground
                    )
                }
            }
        }
    )
}

data class Musics(
    val musicName: String = ""
)

enter image description here