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

DropdownButton2重复value断言错误求助(GetX+DropdownButtonHideUnderline)

问题:DropdownButton2 断言错误(重复value或无匹配value)

使用DropdownButtonHideUnderline组件,通过GetX管理状态时,触发DropdownButton2断言错误,提示「检测到0个或2个及以上拥有相同value的DropdownMenuItem」,怀疑问题出在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列表中存在且唯一,触发错误的常见场景:

  • TaskTest类未重写==运算符和hashCode,导致对象按引用而非内容比较,出现"明明相同却不匹配"或"重复项被判定为不同"的矛盾。
  • selectedValue的value不在当前homeCtrl.tasks列表中(比如列表更新后选中项被移除)。
  • homeCtrl.tasks中存在多个内容完全一致的TaskTest对象,导致匹配到多个项。

具体修复步骤

1. 给TaskTest类重写==和hashCode

因为用TaskTest对象作为value,默认的引用比较无法满足业务逻辑,必须按内容比较:

class TaskTest {
  final String title;
  final int icon;
  final String color;

  TaskTest(this.title, this.icon, this.color);

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) return true;
    return other is TaskTest &&
        other.title == title &&
        other.icon == icon &&
        other.color == color;
  }

  @override
  int get hashCode => Object.hash(title, icon, color);
}

2. 确保选中值始终在列表中

如果tasks列表动态更新,需在更新后校验选中项是否存在,不存在则重置:

// HomeController中更新tasks的示例方法
void updateTasks(List<TaskTest> newTasks) {
  tasks.value = newTasks;
  if (!tasks.value.contains(selectedValue.value)) {
    selectedValue.value = null;
  }
}

3. 确保tasks列表无重复项

检查homeCtrl.tasks是否存在重复的TaskTest对象,可通过去重处理:

// 方式1:利用Set去重(前提是已重写==和hashCode)
List<TaskTest> uniqueTasks = homeCtrl.tasks.toSet().toList();

// 方式2:自定义去重逻辑
List<TaskTest> uniqueTasks = [];
for (var task in homeCtrl.tasks) {
  if (!uniqueTasks.any((t) => t == task)) {
    uniqueTasks.add(task);
  }
}

4. 调试排查(可选)

若仍未定位问题,可添加调试代码查看匹配数量:

// 在生成items后添加调试代码
final items = homeCtrl.tasks.map(...).toList();
final matchCount = items.where((item) => item.value == homeCtrl.selectedValue.value).length;
print("匹配到的项数量:$matchCount");

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:18:35