Jetpack Compose中如何根据一个exposed dropdown menu值过滤另一菜单选项
完全可以实现该需求,核心逻辑是通过Compose的状态托管机制,监听第一个下拉菜单的选中值,动态计算第二个下拉菜单的可选数据源即可,以下是品牌-车型级联选择的具体实现:
实现核心逻辑
- 提前维护品牌与对应车型的映射关系数据
- 通过
remember托管下拉菜单展开状态、选中品牌、选中车型三类状态 - 监听品牌选中事件,品牌变更时自动重置已选车型,同步更新车型下拉的可选列表
- 未选中品牌时可将车型下拉置为禁用状态,避免无效操作
完整实现代码
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.ExposedDropdownMenuDefaults import androidx.compose.material3.Text import androidx.compose.material3.TextField import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp // 定义品牌-车型数据结构 data class CarBrand( val name: String, val models: List<String> ) // 预置品牌与对应车型数据 val localCarBrandList = listOf( CarBrand("比亚迪", listOf("汉EV", "唐DM-i", "海豹", "元PLUS")), CarBrand("特斯拉", listOf("Model 3", "Model Y", "Model S", "Model X")), CarBrand("丰田", listOf("凯美瑞", "卡罗拉", "汉兰达", "RAV4荣放")) ) @OptIn(ExperimentalMaterial3Api::class) @Composable fun CascadingCarSelector() { // 品牌菜单展开状态 var brandMenuExpanded by remember { mutableStateOf(false) } // 车型菜单展开状态 var modelMenuExpanded by remember { mutableStateOf(false) } // 当前选中的品牌 var currentSelectedBrand by remember { mutableStateOf<CarBrand?>(null) } // 当前选中的车型 var currentSelectedModel by remember { mutableStateOf("") } Column( modifier = Modifier .padding(16.dp) .fillMaxWidth(), verticalArrangement = Arrangement.spacedBy(16.dp) ) { // 品牌选择下拉框 ExposedDropdownMenuBox( expanded = brandMenuExpanded, onExpandedChange = { brandMenuExpanded = !brandMenuExpanded } ) { TextField( value = currentSelectedBrand?.name ?: "请选择汽车品牌", onValueChange = {}, readOnly = true, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = brandMenuExpanded) }, modifier = Modifier .menuAnchor() .fillMaxWidth() ) ExposedDropdownMenu( expanded = brandMenuExpanded, onDismissRequest = { brandMenuExpanded = false } ) { localCarBrandList.forEach { brand -> DropdownMenuItem( text = { Text(text = brand.name) }, onClick = { currentSelectedBrand = brand // 切换品牌时重置已选车型,避免数据不匹配 currentSelectedModel = "" brandMenuExpanded = false } ) } } } // 车型选择下拉框 ExposedDropdownMenuBox( expanded = modelMenuExpanded, onExpandedChange = { // 未选择品牌时不允许展开车型菜单 if (currentSelectedBrand != null) { modelMenuExpanded = !modelMenuExpanded } } ) { TextField( value = currentSelectedModel.ifEmpty { "请选择对应车型" }, onValueChange = {}, readOnly = true, enabled = currentSelectedBrand != null, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = modelMenuExpanded) }, modifier = Modifier .menuAnchor() .fillMaxWidth() ) ExposedDropdownMenu( expanded = modelMenuExpanded, onDismissRequest = { modelMenuExpanded = false } ) { // 直接渲染当前选中品牌对应的车型列表 currentSelectedBrand?.models?.forEach { model -> DropdownMenuItem( text = { Text(text = model) }, onClick = { currentSelectedModel = model modelMenuExpanded = false } ) } } } } }
注意事项:切换品牌时必须清空之前选中的车型值,否则会出现选中车型不属于当前品牌的逻辑错误;如果车型数据需要从接口拉取,可以在品牌选中的回调里触发网络请求,将返回的车型列表赋值给状态即可,逻辑和本地数据过滤完全一致。
内容的提问来源于stack exchange,提问作者Jordan Akinpelu
相关产品推荐
相关产品推荐

