Flutter中DropdownButton2重复value值异常求助
问题描述
使用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列表中有且仅有一个匹配项,触发异常的常见原因:
- 自定义类
TaskTest未重写==运算符和hashCode,导致对象比较使用引用而非内容,出现匹配异常; tasks列表中存在重复的TaskTest对象;- 选中的
selectedValue.value不在当前tasks列表中。
解决方法
重写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; }去重tasks列表
确保列表中无重复对象,可使用LinkedHashSet保持顺序并去重:// 更新tasks时调用 homeCtrl.tasks = LinkedHashSet<TaskTest>.from(originalTasks).toList();同步选中值与tasks列表
更新tasks后检查选中值是否存在,不存在则重置为null:void updateTasks(List<TaskTest> newTasks) { tasks.assignAll(newTasks); if (!tasks.contains(selectedValue.value)) { selectedValue.value = null; } }调试排查
临时添加打印,查看每个item与选中值的匹配情况:items: homeCtrl.tasks.map((element) { print('Item: ${element.title}, Selected: ${homeCtrl.selectedValue.value?.title}, Match: ${element == homeCtrl.selectedValue.value}'); // 原有代码 }).toList(),
内容的提问来源于stack exchange,提问作者peyman
相关产品推荐
相关产品推荐

