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

Kotlin复用列表实现DropDownMenu时出现重复条目与空行问题

问题分析与修复方案

核心问题总结

  • 三个下拉框共用同一个expanded状态变量,导致展开/关闭状态互相干扰,引发菜单渲染异常
  • 只读TextField的onValueChange逻辑冗余且错误,无意义操作干扰状态管理
  • choice1/choice2未与外部选中值同步,导致选项过滤逻辑失效,出现重复选项
  • 状态管理混乱导致下拉菜单出现空白行、选项重复等问题

修复后的完整代码

// 复用的选项列表
val options = rememberSaveable {
    listOf(
        "Hindsight", "Ready When You Are", "The Way We Are", "Blow",
        "Blurry Eyed", "Better Off Dead", "Old Habits", 
        "ShallowGrave", "Bullet In The Head", "Dead Weight", 
        "Insomniac", "Follow Me Down", "On My Own", "Bleed You Dry", 
        "Reflections", "Mirrors", "Nowhere Left"
    )
}

// 传入组合式函数
ExposedDropdownMenuSongs(
    songVar = songVar,
    songVarChanged = { newSongVar -> songVar = newSongVar },
    options = options,
    selectedOptions = selectedOptions,
    songVar2 = songVar2,
    songVarChanged2 = { newSongVar -> songVar2 = newSongVar },
    songVar3 = songVar3,
    songVarChanged3 = { newSongVar -> songVar3 = newSongVar }
)

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ExposedDropdownMenuSongs(
    songVar: String,
    songVarChanged: (String) -> Unit,
    options: List<String>,
    selectedOptions: MutableState<List<String>>,
    songVar2: String,
    songVarChanged2: (String) -> Unit,
    songVar3: String,
    songVarChanged3: (String) -> Unit
) {
    Column {
        // 第一个下拉框:独立状态
        var expanded1 by remember { mutableStateOf(false) }
        ExposedDropdownMenuBox(
            expanded = expanded1,
            onExpandedChange = { expanded1 = !expanded1 }
        ) {
            CompositionLocalProvider(LocalTextInputService provides null) {
                TextField(
                    readOnly = true,
                    value = songVar,
                    onValueChange = {}, // 只读TextField无需处理输入
                    label = { Text("Song1:") },
                    modifier = Modifier.menuAnchor()
                )
            }
            ExposedDropdownMenu(
                expanded = expanded1,
                onDismissRequest = { expanded1 = false }
            ) {
                options.forEach { option ->
                    DropdownMenuItem(
                        text = { Text(option) },
                        onClick = {
                            songVarChanged(option)
                            // 更新已选列表
                            selectedOptions.value = selectedOptions.value.toMutableList().apply {
                                removeIf { it == songVar }
                                add(option)
                            }
                            expanded1 = false
                        }
                    )
                }
            }
        }

        // 第二个下拉框:仅在第一个有选择时显示
        if (songVar.isNotEmpty()) {
            var expanded2 by remember { mutableStateOf(false) }
            ExposedDropdownMenuBox(
                expanded = expanded2,
                onExpandedChange = { expanded2 = !expanded2 }
            ) {
                CompositionLocalProvider(LocalTextInputService provides null) {
                    TextField(
                        readOnly = true,
                        value = songVar2,
                        onValueChange = {},
                        label = { Text("Song2:") },
                        modifier = Modifier.menuAnchor()
                    )
                }
                ExposedDropdownMenu(
                    expanded = expanded2,
                    onDismissRequest = { expanded2 = false }
                ) {
                    options.filter { it != songVar }.forEach { option ->
                        DropdownMenuItem(
                            text = { Text(option) },
                            onClick = {
                                songVarChanged2(option)
                                selectedOptions.value = selectedOptions.value.toMutableList().apply {
                                    removeIf { it == songVar2 }
                                    add(option)
                                }
                                expanded2 = false
                            }
                        )
                    }
                }
            }
        }

        // 第三个下拉框:仅在第二个有选择时显示
        if (songVar2.isNotEmpty()) {
            var expanded3 by remember { mutableStateOf(false) }
            ExposedDropdownMenuBox(
                expanded = expanded3,
                onExpandedChange = { expanded3 = !expanded3 }
            ) {
                CompositionLocalProvider(LocalTextInputService provides null) {
                    TextField(
                        readOnly = true,
                        value = songVar3,
                        onValueChange = {},
                        label = { Text("Song3:") }, // 修正label错误
                        modifier = Modifier.menuAnchor()
                    )
                }
                ExposedDropdownMenu(
                    expanded = expanded3,
                    onDismissRequest = { expanded3 = false }
                ) {
                    options.filter { it != songVar && it != songVar2 }.forEach { option ->
                        DropdownMenuItem(
                            text = { Text(option) },
                            onClick = {
                                songVarChanged3(option)
                                selectedOptions.value = selectedOptions.value.toMutableList().apply {
                                    removeIf { it == songVar3 }
                                    add(option)
                                }
                                expanded3 = false
                            }
                        )
                    }
                }
            }
        }
    }
}

关键修复点说明

  1. 独立状态管理: 每个下拉框使用单独的expanded变量(expanded1/expanded2/expanded3),彻底解决状态联动问题
  2. 移除无效逻辑: 只读TextField的onValueChange不会触发,直接留空避免干扰
  3. 同步过滤逻辑: 直接用外部传入的songVar/songVar2替代choice1/choice2,确保过滤的选项始终是最新选中值
  4. 修正UI错误: 第三个下拉框的label从"Song2:"改为"Song3:"
  5. 简化状态更新: 在选项点击时直接更新selectedOptions,避免冗余的中间变量操作

内容的提问来源于stack exchange,提问作者The Quackiest

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:43:24