Flutter中DropdownButton默认值设置失败,运行时报错求助
我在Flutter项目中使用GetX框架实现DropdownButtonFormField时,编译阶段无报错,但运行时触发如下断言错误:
'Package:flutter/src/material/dropdown.dart':Failed assertion : line 1606 pos 15: items==null || items.isEmpty || value==null || items.where ((DropdownMenuItem <T> item){ return item.value == value;}).length == 1': There should be exactly one item with [DropdownButton]'s value:. Either zero or 2 or more [DropdownButton]'s were detected with the same value.
自定义Dropdown组件代码
import 'package:flutter/material.dart'; import 'package:get/get.dart'; class MyStatesDropdown extends StatelessWidget { final String value; final Function(String newValue) onChanged; final List<Map<String, String>> items; MyStatesDropdown( {super.key, required this.value, required this.onChanged, required this.items}); @override Widget build(BuildContext context) { return Obx(() => Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: DropdownButtonFormField( decoration: InputDecoration( isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5.0)), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5.0)), hintText: 'Select State', hintStyle: TextStyle(color: Colors.grey.shade800)), value: value, onChanged: (newVal) => onChanged(newVal ?? ''), items: items.map((Map item) { return DropdownMenuItem<String>( value: item['scode'], child: Text(item['sname'])); }).toList(), icon: Icon(Icons.arrow_drop_down), iconSize: 42, )), ], )); } }
GetX控制器代码
................. final istates = [ {'scode': '35', 'sname': 'Andaman & Nicobar Islands'}, {'scode': '37', 'sname': 'Andhra Pradesh'}, {'scode': '12', 'sname': 'Arunachal Pradesh'}, {'scode': '18', 'sname': 'Assam'}, {'scode': '10', 'sname': 'Bihar'}, {'scode': '04', 'sname': 'Chandigarh'}, {'scode': '22', 'sname': 'Chattisgarh'}, {'scode': '26', 'sname': 'Dadra & Nagar Haveli & Daman & Diu'}, {'scode': '07', 'sname': 'Delhi'}, {'scode': '30', 'sname': 'Goa'}, {'scode': '24', 'sname': 'Gujarat'}, {'scode': '06', 'sname': 'Haryana'}, {'scode': '02', 'sname': 'Himachal Pradesh'}, {'scode': '01', 'sname': 'Jammu & Kashmir'}, {'scode': '20', 'sname': 'Jharkhand'}, {'scode': '29', 'sname': 'Karnataka'}, {'scode': '32', 'sname': 'Kerala'}, {'scode': '38', 'sname': 'Ladakh'}, {'scode': '31', 'sname': 'Lakshwadeep'}, {'scode': '23', 'sname': 'Madhya Pradesh'}, {'scode': '27', 'sname': 'Maharashtra'}, {'scode': '14', 'sname': 'Manipur'}, {'scode': '17', 'sname': 'Meghalaya'}, {'scode': '15', 'sname': 'Mizoram'}, {'scode': '13', 'sname': 'Nagaland'}, {'scode': '21', 'sname': 'Odisha'}, {'scode': '34', 'sname': 'Puducherry'}, {'scode': '03', 'sname': 'Punjab'}, {'scode': '08', 'sname': 'Rajasthan'}, {'scode': '11', 'sname': 'Sikkim'}, {'scode': '33', 'sname': 'Tamil Nadu'}, {'scode': '36', 'sname': 'Telangana'}, {'scode': '16', 'sname': 'Tripura'}, {'scode': '09', 'sname': 'Uttar Pradesh'}, {'scode': '15', 'sname': 'Uttrakhand'}, {'scode': '19', 'sname': 'West Bengal'} ]; var selectedStateSA = ''.obs; void updtSelectedStateSA(String val) { selectedStateSA.value = val; } ...............
页面调用组件代码
........... MyStatesDropdown( value: _genContllr.selectedStateSA.value, onChanged: (newValue) => _genContllr .updtSelectedStateSA(newValue), items: _genContllr.istates), ...........
问题原因及修复方案
1. 数据源重复值问题
你的istates列表中,Mizoram和Uttrakhand的scode均为'15',导致DropdownButton匹配到两个相同值,触发断言错误。需修改重复的scode为唯一值,例如:
{'scode': '05', 'sname': 'Uttrakhand'},
2. 默认值初始化问题
当前默认值为空字符串'',但数据源中无对应选项,同样会触发断言。有两种处理方式:
- 方式一:设置有效默认值
将selectedStateSA初始化为数据源中存在的scode,比如:
var selectedStateSA = '35'.obs; // 对应Andaman & Nicobar Islands
- 方式二:允许空初始状态(显示hint)
若需默认显示提示文本、不选中任何选项,需修改以下内容:- 控制器中修改变量类型为可空字符串:
var selectedStateSA = RxString?(); - 自定义组件更新参数类型及Dropdown配置:
class MyStatesDropdown extends StatelessWidget { final String? value; // 改为可空类型 final Function(String newValue) onChanged; final List<Map<String, String>> items; MyStatesDropdown( {super.key, required this.value, required this.onChanged, required this.items}); @override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Obx(() => DropdownButtonFormField<String>( decoration: InputDecoration( isDense: true, border: OutlineInputBorder( borderRadius: BorderRadius.circular(5.0)), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(5.0)), hintText: 'Select State', hintStyle: TextStyle(color: Colors.grey.shade800)), value: value, onChanged: (newVal) { if (newVal != null) onChanged(newVal); }, items: items.map((Map item) { return DropdownMenuItem<String>( value: item['scode'], child: Text(item['sname'])); }).toList(), icon: Icon(Icons.arrow_drop_down), iconSize: 42, ))), ], ); } }
- 控制器中修改变量类型为可空字符串:
3. 组件优化建议
将Obx的包裹范围缩小至DropdownButtonFormField,避免不必要的UI重建:
@override Widget build(BuildContext context) { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Center( child: Obx(() => DropdownButtonFormField<String>( // 原有配置不变 ))), ], ); }
内容的提问来源于stack exchange,提问作者gomesh munda
相关产品推荐
相关产品推荐

