Flutter DropdownMenu开启enableFilter后选择非第一项触发越界错误
开启enableFilter: true后,DropdownMenu选择除第一项外的任何选项都会崩溃,抛出RangeError Index out of range错误;设置enableFilter: false则无此问题。
已完成的排查:
- 确认
LevelOfBadness枚举的每个选项都对应了DropdownMenuEntry - 打印日志验证数据类型和值均正常
原因分析
这是Flutter框架的已知问题,和你参考的StackOverflow问题属于同一类场景:当DropdownMenu以枚举作为泛型类型且启用过滤功能时,框架内部处理选中项索引时出现逻辑错误——错误地将枚举自身的索引(比如LevelOfBadness.X的索引为5)直接当作过滤后列表的索引使用,当过滤后的列表长度不足或索引不匹配时,就会触发越界异常。
修复方案
方案1:添加initialSelection绑定选中状态
给DropdownMenu添加initialSelection参数,将其与你的选中变量绑定,让框架能正确关联选中项和列表条目:
DropdownMenu( enableFilter: true, initialSelection: selectedBadnessRating, // 新增该行 onSelected: (currentBadnessSelectedInDropdownMenu) { if (currentBadnessSelectedInDropdownMenu != null) { setState(() { log("Type is: " + currentBadnessSelectedInDropdownMenu.runtimeType.toString()); log("Value is: " + currentBadnessSelectedInDropdownMenu.toString()); selectedBadnessRating = currentBadnessSelectedInDropdownMenu; }); } }, dropdownMenuEntries: const <DropdownMenuEntry<LevelOfBadness>>[ DropdownMenuEntry(value: LevelOfBadness.I, label: "Underwhelming"), DropdownMenuEntry(value: LevelOfBadness.II, label: "Rookie"), DropdownMenuEntry(value: LevelOfBadness.III, label: "Moderate"), DropdownMenuEntry(value: LevelOfBadness.IV, label: "Fully-Operational"), DropdownMenuEntry(value: LevelOfBadness.V, label: "Level 5 Baddie"), DropdownMenuEntry(value: LevelOfBadness.X, label: "Mega-baddie!"), ], ),
方案2:改用非枚举类型作为泛型(临时规避)
如果暂时不想依赖框架修复,可以将枚举转换为字符串/整数作为DropdownMenu的泛型类型,通过映射关系关联回枚举值:
// 提前定义映射列表 final List<Map<String, dynamic>> badnessRatingItems = [ {"enumValue": LevelOfBadness.I, "label": "Underwhelming"}, {"enumValue": LevelOfBadness.II, "label": "Rookie"}, {"enumValue": LevelOfBadness.III, "label": "Moderate"}, {"enumValue": LevelOfBadness.IV, "label": "Fully-Operational"}, {"enumValue": LevelOfBadness.V, "label": "Level 5 Baddie"}, {"enumValue": LevelOfBadness.X, "label": "Mega-baddie!"}, ]; // 使用String作为泛型的DropdownMenu DropdownMenu<String>( enableFilter: true, onSelected: (String? selectedLabel) { if (selectedLabel != null) { setState(() { selectedBadnessRating = badnessRatingItems.firstWhere((item) => item["label"] == selectedLabel)["enumValue"]; }); } }, dropdownMenuEntries: badnessRatingItems .map((item) => DropdownMenuEntry(value: item["label"], label: item["label"])) .toList(), ),
额外解决:重置时清空选中状态
你提到的重置时无法取消选中的问题,只需在重置方法中将selectedBadnessRating设为null,配合方案1的initialSelection就能正常清空:
void onPressedReset() { setState(() { tfc.text = ""; theBiggestVillian = null; selectedBadnessRating = null; // 现在可正常清空选中状态 log("Reset ran"); }); }
内容的提问来源于stack exchange,提问作者kmort
相关产品推荐
相关产品推荐

