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

Flutter中DropdownButton2重复value值异常求助

Flutter DropdownButton2 重复值异常解决

问题描述

使用DropdownButtonHideUnderline组件结合GetX管理DropdownButton2状态时,抛出异常:

Either zero or 2 or more [DropdownMenuItem]s were detected with the same value

怀疑问题出在DropdownButton2的value属性上。

组件代码

DropdownButtonHideUnderline(
  child: Obx(
    () => DropdownButton2(
      isExpanded: true,
      hint: Row(
        children: const [
          Icon(
            Icons.list,
            size: 16,
            color: Colors.yellow,
          ),
          SizedBox(
            width: 4,
          ),
          Expanded(
            child: Text(
              'Add to',
              style: TextStyle(
                fontSize: 14,
                fontWeight: FontWeight.bold,
                color: Colors.yellow,
              ),
              overflow: TextOverflow.ellipsis,
            ),
          ),
        ],
      ),
      items: homeCtrl.tasks.map(
        (element) {
          final color = HexColor(element.color);
          return DropdownMenuItem<TaskTest>(
            value: element,
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Row(
                  children: [
                    Icon(
                      IconData(element.icon, fontFamily: 'MaterialIcons'),
                      color: color,
                    ),
                    SizedBox(
                      width: 10,
                    ),
                    Text(
                      element.title,
                      overflow: TextOverflow.ellipsis,
                    ),
                  ],
                ),
                if (homeCtrl.selectedValue.value == element)
                  FaIcon(FontAwesomeIcons.circleCheck, color: customColor.kBlue),
              ],
            ),
          );
        },
      ).toList(),
      value: homeCtrl.selectedValue.value,
      onChanged: (value) => homeCtrl.setDropDownValue(value as TaskTest),
      icon: const Icon(
        Icons.arrow_forward_ios_outlined,
      ),
      iconSize: 14,
      iconEnabledColor: Colors.yellow,
      iconDisabledColor: Colors.grey,
      buttonHeight: 35,
      buttonWidth: double.infinity,
      buttonPadding: const EdgeInsets.only(left: 14, right: 14),
      buttonDecoration: BoxDecoration(
        gradient: kPinkGradient,
        borderRadius: BorderRadius.circular(14),
        border: Border.all(
          color: Colors.black26,
        ),
        color: Colors.deepPurpleAccent,
      ),
      buttonElevation: 2,
      itemHeight: 30,
      itemPadding: const EdgeInsets.only(left: 14, right: 14),
      dropdownMaxHeight: 200,
      dropdownWidth: 200,
      dropdownPadding: null,
      dropdownDecoration: BoxDecoration(
        gradient: kPinkGradient,
        borderRadius: BorderRadius.circular(14),
        color: Colors.deepPurpleAccent,
      ),
      dropdownElevation: 8,
      scrollbarRadius: const Radius.circular(40),
      scrollbarThickness: 6,
      scrollbarAlwaysShow: true,
      offset: const Offset(-20, 0),
    ),
  ),
),

HomeController代码

状态变量

final selectedValue = Rx<TaskTest?>(null);

切换方法

void setDropDownValue(TaskTest? newValue) {
  selectedValue.value = newValue;
}

错误信息

======== Exception caught by widgets library =======================================================
The following assertion was thrown building Obx(has builder, dirty, state: _ObxState#78790):
There should be exactly one item with [DropdownButton]'s value: TaskTest(health, 59737, #FFfa63c6). 
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
'package:dropdown_button2/dropdown_button2.dart':
Failed assertion: line 968 pos 11: 'items == null ||
              items.isEmpty ||
              value == null ||
              items.where((DropdownMenuItem<T> item) {
                    return item.value == value;
                  }).length ==
                  1'

The relevant error-causing widget was: 
  Obx Obx:file:///E:/flutter-projects-licotab/bootcamp/task_managment_test/lib/widgets/task_sheet.dart:494:30
When the exception was thrown, this was the stack: 
#2      new DropdownButton2 (package:dropdown_button2/dropdown_button2.dart:968:11)

问题原因与解决步骤

核心原因

DropdownButton2要求选中的value必须在items列表中有且仅有一个匹配项,触发异常的常见原因:

  1. 自定义类TaskTest未重写==运算符和hashCode,导致对象比较使用引用而非内容,出现匹配异常;
  2. tasks列表中存在重复的TaskTest对象;
  3. 选中的selectedValue.value不在当前tasks列表中。

解决方法

  1. 重写TaskTest的相等性判断方法
    自定义类默认用引用比较,需基于业务属性重写==和hashCode:

    class TaskTest {
      final String title;
      final int icon;
      final String color;
    
      TaskTest(this.title, this.icon, this.color);
    
      @override
      bool operator ==(Object other) =>
          identical(this, other) ||
          other is TaskTest &&
              runtimeType == other.runtimeType &&
              title == other.title &&
              icon == other.icon &&
              color == other.color;
    
      @override
      int get hashCode => title.hashCode ^ icon.hashCode ^ color.hashCode;
    }
    
  2. 去重tasks列表
    确保列表中无重复对象,可使用LinkedHashSet保持顺序并去重:

    // 更新tasks时调用
    homeCtrl.tasks = LinkedHashSet<TaskTest>.from(originalTasks).toList();
    
  3. 同步选中值与tasks列表
    更新tasks后检查选中值是否存在,不存在则重置为null:

    void updateTasks(List<TaskTest> newTasks) {
      tasks.assignAll(newTasks);
      if (!tasks.contains(selectedValue.value)) {
        selectedValue.value = null;
      }
    }
    
  4. 调试排查
    临时添加打印,查看每个item与选中值的匹配情况:

    items: homeCtrl.tasks.map((element) {
      print('Item: ${element.title}, Selected: ${homeCtrl.selectedValue.value?.title}, Match: ${element == homeCtrl.selectedValue.value}');
      // 原有代码
    }).toList(),
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 13:48:19