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

Flutter联动DropdownButtonFormField切换时出现同值错误求助

联动DropdownButtonFormField切换父选项后报错的解决方法

问题重现

页面有两个联动的DropdownButtonFormField,第二个下拉框的选项随第一个的选择动态加载。执行以下操作触发断言错误:

  1. 选择第一个下拉框的某选项
  2. 选择第二个下拉框的某选项
  3. 修改第一个下拉框的选中值

错误信息:

There should be exactly one item with [DropdownButtonFormField]'s value: 1789.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:flutter/src/material/dropdown.dart':
dropdown.dart:1
Failed assertion: line 933 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem item) {
return item.value == value;
}).length == 1'

原代码实现

DropdownButtonFormField<int?>(
  value: userController.selectedReturnCity,
  items: List.generate(
    userController.storeCityFilter?.length ?? 0,
    (index) => DropdownMenuItem(
      value: userController.storeCityFilter![index]['id'],
      child: Text(userController.storeCityFilter![index]['value'])
    )
  ),
  onChanged: (value) async {
    userController.selectedReturnCity = value == 0 ? null : value;
    // 获取第二个下拉框数据,该方法会清空原有的选项数据
    await userController.getStores(
      city: userController.selectedReturnCity, 
      type: "market"
    );
  },
),
10.v(),
DropdownButtonFormField<int?>(
  value: userController.selectedReturnStore,
  items: List.generate(
    userController.storeList?.length ?? 0,
    (index) => DropdownMenuItem<int?>(
      value: userController.storeList?[index].id,
      child: Text(userController.storeList?[index].name ?? '')
    )
  ),
  onChanged: (value) {
    userController.selectedReturnStore = value;
  },
)

错误根源

修改第一个下拉框选项时,第二个下拉框的storeList会被重新加载(甚至清空),但selectedReturnStore仍保留着之前选中的旧值。此时新的storeList中没有对应旧值的选项,导致DropdownButtonFormField的value不在当前items列表中,触发Flutter的断言检查失败。

修复方案

方案1:切换父选项时重置子下拉框选中值

直接在第一个下拉框的onChanged回调中,先重置第二个下拉框的选中值,再加载新数据:

onChanged: (value) async {
  userController.selectedReturnCity = value == 0 ? null : value;
  // 重置子下拉框选中值,避免旧值与新选项不匹配
  userController.selectedReturnStore = null;
  await userController.getStores(
    city: userController.selectedReturnCity, 
    type: "market"
  );
},

方案2:数据加载后校验选中值有效性

在getStores方法内部,数据加载完成后,校验当前selectedReturnStore是否存在于新的选项列表中,不存在则设为null:

// 假设getStores是Controller中的方法,数据加载完成后添加以下逻辑
void getStores({int? city, String type}) async {
  // ... 原有数据请求逻辑 ...
  storeList = 新加载的门店列表;
  
  // 校验选中值有效性
  final validStoreIds = storeList?.map((store) => store.id).toList() ?? [];
  if (selectedReturnStore != null && !validStoreIds.contains(selectedReturnStore)) {
    selectedReturnStore = null;
    // 如果用了状态管理(比如GetX),需要确保状态更新通知UI
    update();
  }
}

方案1简单直接,适合大多数场景;方案2更严谨,能覆盖其他可能导致选中值失效的情况。

内容的提问来源于stack exchange,提问作者Baran Güngör

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:52:11