You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ExposedDropdownMenu创建按顺序填写的多步骤表单?

实现按顺序强制填写的表单(禁用后续输入)

核心逻辑是每个后续输入框的启用状态依赖于前一个输入是否已完成,通过控制enabled属性来锁定未到顺序的输入,配合你已有的FocusManager跳转逻辑,就能实现「Choice A→Choice B→Choice C→Choice D」的强制填写顺序。

具体实现步骤

  1. 定义状态变量存储每个选项的选中值,用于判断后续输入框的启用状态
  2. 为每个ExposedDropdownMenuBox及内部TextField设置enabled条件
  3. 保留原有的焦点跳转逻辑,确保用户完成当前选项后自动聚焦到下一个可用输入

示例代码实现

@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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 14:52:30