如何用ExposedDropdownMenu创建按顺序填写的多步骤表单?
实现按顺序强制填写的表单(禁用后续输入)
核心逻辑是每个后续输入框的启用状态依赖于前一个输入是否已完成,通过控制enabled属性来锁定未到顺序的输入,配合你已有的FocusManager跳转逻辑,就能实现「Choice A→Choice B→Choice C→Choice D」的强制填写顺序。
具体实现步骤
- 定义状态变量存储每个选项的选中值,用于判断后续输入框的启用状态
- 为每个
ExposedDropdownMenuBox及内部TextField设置enabled条件 - 保留原有的焦点跳转逻辑,确保用户完成当前选项后自动聚焦到下一个可用输入
示例代码实现
@Composable fun SequentialForm() { // 存储每个选项的选中值,初始为null表示未完成 var selectedA by remember { mutableStateOf<String?>(null) } var selectedB by remember { mutableStateOf<String?>(null) } var selectedC by remember { mutableStateOf<String?>(null) } var selectedD by remember { mutableStateOf<String?>(null) } // 下拉菜单展开状态 var expandedA by remember { mutableStateOf(false) } var expandedB by remember { mutableStateOf(false) } var expandedC by remember { mutableStateOf(false) } var expandedD by remember { mutableStateOf(false) } val focusManager = LocalFocusManager.current val columnScope = Column(modifier = Modifier.padding(16.dp), verticalArrangement = Arrangement.spacedBy(16.dp)) { // Choice A - 始终可用 ExposedDropdownMenuBox( expanded = expandedA, onExpandedChange = { expandedA = it }, enabled = true ) { TextField( value = selectedA ?: "请选择Choice A", onValueChange = {}, readOnly = true, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expandedA) }, modifier = Modifier.menuAnchor() ) ExposedDropdownMenu( expanded = expandedA, onDismissRequest = { expandedA = false } ) { listOf("选项1", "选项2", "选项3").forEach { option -> DropdownMenuItem( text = { Text(option) }, onClick = { selectedA = option expandedA = false // 选中后自动跳转至Choice B focusManager.moveFocus(FocusDirection.Down) } ) } } } // Choice B - 仅当Choice A选中后可用 ExposedDropdownMenuBox( expanded = expandedB, onExpandedChange = { if (selectedA != null) expandedB = it }, enabled = selectedA != null ) { TextField( value = selectedB ?: "请选择Choice B", onValueChange = {}, readOnly = true, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expandedB) }, modifier = Modifier.menuAnchor(), enabled = selectedA != null // 同步TextField的禁用状态 ) ExposedDropdownMenu( expanded = expandedB, onDismissRequest = { expandedB = false } ) { listOf("选项X", "选项Y", "选项Z").forEach { option -> DropdownMenuItem( text = { Text(option) }, onClick = { selectedB = option expandedB = false focusManager.moveFocus(FocusDirection.Down) } ) } } } // Choice C - 仅当Choice B选中后可用 ExposedDropdownMenuBox( expanded = expandedC, onExpandedChange = { if (selectedB != null) expandedC = it }, enabled = selectedB != null ) { TextField( value = selectedC ?: "请选择Choice C", onValueChange = {}, readOnly = true, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expandedC) }, modifier = Modifier.menuAnchor(), enabled = selectedB != null ) ExposedDropdownMenu( expanded = expandedC, onDismissRequest = { expandedC = false } ) { listOf("选项α", "选项β", "选项γ").forEach { option -> DropdownMenuItem( text = { Text(option) }, onClick = { selectedC = option expandedC = false focusManager.moveFocus(FocusDirection.Down) } ) } } } // Choice D - 仅当Choice C选中后可用 ExposedDropdownMenuBox( expanded = expandedD, onExpandedChange = { if (selectedC != null) expandedD = it }, enabled = selectedC != null ) { TextField( value = selectedD ?: "请选择Choice D", onValueChange = {}, readOnly = true, trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expandedD) }, modifier = Modifier.menuAnchor(), enabled = selectedC != null ) ExposedDropdownMenu( expanded = expandedD, onDismissRequest = { expandedD = false } ) { listOf("选项Ⅰ", "选项Ⅱ", "选项Ⅲ").forEach { option -> DropdownMenuItem( text = { Text(option) }, onClick = { selectedD = option expandedD = false } ) } } } } }
关键细节说明
- 每个下拉框的
enabled属性直接绑定前一个选项的选中状态(非空即表示已完成) - 要同时给
ExposedDropdownMenuBox和内部的TextField设置enabled,确保整个组件(包括展开菜单的点击功能)都处于禁用状态 - 保留你原有的
FocusManager跳转逻辑,用户完成当前选项后自动聚焦到下一个,提升填写流畅度
内容的提问来源于stack exchange,提问作者Joe Mama Jr.
相关产品推荐
相关产品推荐

