Flutter动态级联下拉菜单选中值异常问题求助
需求:实现基于API的动态级联下拉菜单
- 初始加载一级下拉选项;
- 选中任意层级选项时,调用API加载其子级并新增下拉菜单,直至无子级;
- 修改任意层级选项时,删除后续所有下拉菜单并重新加载对应子级。
当前问题
点击添加按钮新增下拉菜单时,抛出异常:Another exception was thrown: There should be exactly one item with [DropdownButton]'s value: .。若将DropdownButton的value设为null,则无法正常显示选中值,需要解决该矛盾。
问题根源
- 空值不匹配:添加新下拉时,调用
updateBuildingOptions(nestedListArrayNames[level], "")传入空字符串作为选中值,但如果目标选项列表中没有空字符串,DropdownButton会触发报错——它要求value必须存在于items列表中。 - 状态同步逻辑缺陷:DynamicWidget内部的
dropdownValue初始化和更新逻辑冗余,且未处理父组件传入参数变化的场景。
修复方案
1. 重构DynamicWidget状态逻辑
去掉冗余代码,确保dropdownValue始终与选项列表匹配:
class _DynamicWidgetState extends State<DynamicWidget> { late String dropdownValue; @override void initState() { super.initState(); // 初始化时校验选中值,不存在则取第一个选项 dropdownValue = widget.item.contains(widget.selectedValue) ? widget.selectedValue : widget.item.isNotEmpty ? widget.item[0] : ''; } @override void didUpdateWidget(covariant DynamicWidget oldWidget) { super.didUpdateWidget(oldWidget); // 父组件参数变化时,同步更新选中值 if (oldWidget.item != widget.item || oldWidget.selectedValue != widget.selectedValue) { setState(() { dropdownValue = widget.item.contains(widget.selectedValue) ? widget.selectedValue : widget.item.isNotEmpty ? widget.item[0] : ''; }); } } @override Widget build(BuildContext context) { if (widget.item.isEmpty) return SizedBox(); return DropdownButton<String>( value: dropdownValue.isEmpty && widget.item.isNotEmpty ? widget.item[0] : dropdownValue, items: widget.item.map<DropdownMenuItem<String>>((String value) { return DropdownMenuItem<String>( value: value, child: Container( width: MediaQuery.of(context).size.width / 3.8, child: Container( decoration: BoxDecoration( border: Border( bottom: BorderSide(color: kBlack, width: 1.0), ), ), child: Text( value, textAlign: TextAlign.center, style: TextStyle(fontSize: 16), overflow: TextOverflow.ellipsis, ), ), ), ); }).toList(), onChanged: (newValue) { if (newValue == null) return; setState(() => dropdownValue = newValue); widget.onChangeElement(dropdownValue); }, ); } }
2. 修正添加下拉时的参数传递
在FloatingActionButton的点击事件中,将空字符串替换为实际选中值:
// 原代码 updateBuildingOptions(nestedListArrayNames[level], ""); // 修改为 updateBuildingOptions(nestedListArrayNames[level], selectedBuild);
3. 处理无子级的边界情况
当API返回无子级时,不添加空下拉菜单:
// 在添加下拉的逻辑中增加判断 if (buildingUnitChildrenNames.isNotEmpty) { nestedListArrayNames.add(buildingUnitChildrenNames); nestedListArrayIds.add(buildingUnitChildrenIds); selectedBuild = buildingUnitChildrenNames[0]; selectedBuildingUnitId = buildingUnitChildrenIds[0]; updateBuildingOptions(nestedListArrayNames[level], selectedBuild); } else { selectedBuild = ''; selectedBuildingUnitId = ''; // 无子级时无需添加新下拉 }
额外优化建议
- 将
selectedBuildingUnitName和selectedBuildingUnitId改为数组(如List<String> selectedNames = []),分别跟踪每个下拉的选中状态,避免单一变量的逻辑混淆; - 调用API加载子级时添加加载状态,防止用户重复点击按钮。
内容的提问来源于stack exchange,提问作者DaniaMawlawi
相关产品推荐
相关产品推荐

