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

Flutter动态级联下拉菜单选中值异常问题求助

需求:实现基于API的动态级联下拉菜单
  • 初始加载一级下拉选项;
  • 选中任意层级选项时,调用API加载其子级并新增下拉菜单,直至无子级;
  • 修改任意层级选项时,删除后续所有下拉菜单并重新加载对应子级。

当前问题

点击添加按钮新增下拉菜单时,抛出异常:Another exception was thrown: There should be exactly one item with [DropdownButton]'s value: .。若将DropdownButton的value设为null,则无法正常显示选中值,需要解决该矛盾。

问题根源

  1. 空值不匹配:添加新下拉时,调用updateBuildingOptions(nestedListArrayNames[level], "")传入空字符串作为选中值,但如果目标选项列表中没有空字符串,DropdownButton会触发报错——它要求value必须存在于items列表中。
  2. 状态同步逻辑缺陷: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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:32:33