Is there a way to filter the exposed dropdown menu options depending on the value of another exposed dropdown menu in compose?

Viewed 98

So for example lets say I wanted the user to select a car on a car selection screen. The user would first select the car make they want from the first dropdown and depending on what make they choose the second menu would update and would show all the possible models for that specific make.

1 Answers

You just need to recompose your sub ExposedDropDownMenu with new data. I add a sample

@Composable
private fun SubSelectionComposable() {
    val list = listOf("SelectionA", "SelectionB", "SelectionC")
    val subListA = listOf("SubA1", "SubA2", "SubA3")
    val subListB = listOf("SubB1", "SubB2", "SubB3")
    val subListC = listOf("SubC1", "SubC2", "SubC3")


    var mainSelection by remember { mutableStateOf(-1) }
    var subSelection by remember { mutableStateOf(-1) }

    val subList = remember(mainSelection) {
        when(mainSelection){
            1-> subListB
            2-> subListC
            else-> subListA
        }
    }

    ExposedSelectionMenu(
        modifier =Modifier,
        index = mainSelection,
        options = list,
        title = "Main Selection",
        onSelected = {
            mainSelection = it
            subSelection = 0
        }
    )

    ExposedSelectionMenu(
        modifier =Modifier,
        index = subSelection,
        options = subList,
        title = "Sub Selection",
        onSelected = {
            subSelection = it

        }
    )
}

I set indexes -1 as default, it can be 0 too. Purpose of setting -1 is to know whether user picked anything or not.

Result

enter image description here

This my ExposedMenu, you can have your own

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExposedSelectionMenu(
    modifier: Modifier = Modifier,
    index: Int,
    title: String? = null,
    textStyle: TextStyle = TextStyle(
        fontWeight = FontWeight.W600,
        fontSize = 14.sp
    ),
    colors: TextFieldColors = ExposedDropdownMenuDefaults.textFieldColors(
        containerColor = Color.Transparent,
        focusedIndicatorColor = Color.Transparent,
        unfocusedIndicatorColor = Color.Transparent,
        disabledIndicatorColor = Color.Transparent
    ),
    options: List<String>,
    onSelected: (Int) -> Unit
) {

    var expanded by remember { mutableStateOf(false) }
    var selectedOptionText = options[index.coerceAtLeast(0)]

    ExposedDropdownMenuBox(
        modifier = modifier,
        expanded = expanded,
        onExpandedChange = {
            expanded = !expanded
        }
    ) {
        TextField(
            modifier = modifier,
            readOnly = true,
            value = selectedOptionText,
            onValueChange = { },
            label = {
                title?.let {
                    Text(it)
                }
            },
            trailingIcon = {
                ExposedDropdownMenuDefaults.TrailingIcon(
                    expanded = expanded
                )
            },
            colors = colors,
            textStyle = textStyle
        )
        ExposedDropdownMenu(
            expanded = expanded,
            onDismissRequest = {
                expanded = false

            }
        ) {
            options.forEachIndexed { index: Int, selectionOption: String ->
                DropdownMenuItem(
                    onClick = {
                        selectedOptionText = selectionOption
                        expanded = false
                        onSelected(index)
                    },
                    text = {
                        Text(text = selectionOption)
                    }
                )
            }
        }
    }
}
Related