Flutter联动下拉切换一级报错,如何程序化取消次级选中项
联动下拉报错的根因
Flutter 的DropdownButtonFormField有严格的内置校验规则:只要传入的value不为空,就必须能在当前渲染的items列表中找到完全匹配的唯一值,否则就会直接抛出渲染错误。
你当前的切换场景里刚好踩了三个规则坑:
- 切换城市时,旧的
_weight状态还保留着上一个城市对应的重量id,等新的城市重量列表拉取完成后,这个旧id根本不在新的选项列表里 - 重量下拉的items列表里加了一个写死的
DropdownMenuItem(child: Text("Select Weight")),这个项没有设置独立的value值,本身就不符合下拉组件的校验要求 - 切换城市的逻辑只更新了重量列表,没有同步重置重量下拉的选中状态,必然触发值不匹配的报错
具体修改方案
1. 调整城市下拉的联动逻辑
将接口拉取、状态重置的逻辑统一放到下拉组件的标准onChanged回调里(不要把核心逻辑只写在单个item的onTap中,避免逻辑漏触发),选中城市时同步完成两个操作:
- 把重量下拉的选中值重置为null,实现编程式取消选中
- 清空旧的重量列表,避免新数据加载时残留旧选项
修改后的城市下拉代码:
// Choose City CustomDropDownMenu( items: allCity.map((list) { return DropdownMenuItem( value: list["id"].toString(), child: Padding( padding: const EdgeInsets.only(left: 20.0), child: Text("${list["name"]}"), ), ); }).toList(), value: _city, hint: "Choose City", onChanged: (selectedCityId) { setState(() { _city = selectedCityId; // 核心:切换城市时重置重量下拉的选中状态 _weight = null; // 清空旧重量列表 weightList = []; }); // 拉取当前城市对应的重量选项数据 getWeight(selectedCityId).then((value) { setState(() { weightList = value; }); }); FocusScope.of(context).unfocus(); }, ),
2. 修正重量下拉的结构
删掉那个没有设置value的"Select Weight"固定项——当_weight为null时,组件本来就会自动展示你设置的hint提示文本,这个多余的项不仅没有实际作用,还会因为value不唯一触发校验报错。
修改后的重量下拉代码:
// Weight CustomDropDownMenu( hint: "Select Weight", value: _weight, items: weightList.map((list) { return DropdownMenuItem( value: list["id"].toString(), child: Padding( padding: const EdgeInsets.only(left: 20.0), child: Text("${list["weight"]}"), ), ); }).toList(), onChanged: (selectedWeightId) { setState(() { _weight = selectedWeightId; }); FocusScope.of(context).unfocus(); }, ),
3. 优化自定义下拉组件的类型支持
原来的CustomDropDownMenu硬写了DropdownMenuItem<dynamic>类型,类型不统一也会间接触发校验问题,改成泛型版本匹配Flutter下拉组件的原生类型逻辑:
class CustomDropDownMenu<T> extends StatelessWidget { final String hint; final T value; final Function(T?) onChanged; final Function(T?) onSaved; final List<DropdownMenuItem<T>> items; const CustomDropDownMenu({ Key? key, this.hint, required this.onChanged, this.onSaved, required this.items, this.value, }) : super(key: key); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.circular(60), ), child: Card( shape: const StadiumBorder(), elevation: 5, child: DropdownButtonFormField<T>( style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18.0, color: Colors.black ), hint: Padding( padding: const EdgeInsets.only(left: 20.0), child: Text(hint!), ), decoration: const InputDecoration( enabledBorder: UnderlineInputBorder( borderSide: BorderSide(color: Colors.transparent), ), ), value: value, onChanged: onChanged, onSaved: onSaved, items: items, ), ), ); } }
关于取消选中的实现说明:把
_weight设置为null就是Flutter下拉组件官方支持的取消选中方式——当传入的value为null时,组件不会渲染任何已选中的项,直接展示hint提示文本,完全不需要额外的自定义操作。
内容的提问来源于stack exchange,提问作者Abir Ahsan
相关产品推荐
相关产品推荐

