Flutter下拉框报错:ProductModel实例匹配项数量异常
Flutter分类联动下拉框产品选择报错解决方法
问题现象
开发分类联动产品下拉框时,选择分类后产品列表按分类过滤展示,但选择产品时触发报错:
There should be exactly one item with [DropdownButton]'s value: Instance of 'ProductModel'. Either zero or 2 or more [DropdownMenuItem]s were detected with the same value
直接使用全量产品列表无报错,但无法实现分类筛选需求。
问题原因
报错核心在于ProductModel对象的相等性判断逻辑:
- 切换分类时,
_filteredstoreProdList是通过where过滤生成的新列表,默认情况下Dart对象的==运算符比较的是内存地址而非实际数据。 - 若之前选中过某个ProductModel,切换分类后新过滤列表中即使有数据相同的产品,也会因内存实例不同,导致DropdownButton无法匹配到对应的MenuItem,或误判为多个相同值,最终抛出错误。
解决方案
1. 为ProductModel重写相等性判断
在ProductModel类中重写==运算符和hashCode,基于产品的唯一标识(比如id)判断对象相等:
class ProductModel { final String id; final String name; final String categoryId; // 其他字段根据实际情况添加 ProductModel({ required this.id, required this.name, required this.categoryId, }); @override bool operator ==(Object other) { if (identical(this, other)) return true; return other is ProductModel && other.id == id && other.runtimeType == runtimeType; } @override int get hashCode => id.hashCode; }
2. 切换分类时重置选中产品
在分类下拉框的onChanged回调中,切换分类后将选中的产品置为null,确保DropdownButton的value始终存在于当前过滤后的产品列表中:
onChanged: (CategoryModel value) { setState(() { this._selectedCategory = value; this._filteredstoreProdList = widget.userData.products .where((data) => data.categoryId == value.id) .toList(); // 重置选中产品,避免旧选中项不在新过滤列表中 this._selectedProducts = null; }); },
修改后的完整代码片段
分类下拉框
Widget _prepareCategoryDDL() { return Container( width: 350, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Color.fromRGBO(225, 95, 27, .3), blurRadius: 20, offset: Offset(0, 10)) ], ), child: DropdownButton<CategoryModel>( hint: Text(" Categories"), value: this._selectedCategory, onChanged: (CategoryModel value) { setState(() { this._selectedCategory = value; this._filteredstoreProdList = widget.userData.products .where((data) => data.categoryId == value.id) .toList(); // 重置选中产品 this._selectedProducts = null; }); }, items: widget.userData.categories.map((CategoryModel category) { return DropdownMenuItem<CategoryModel>( value: category, child: Row( children: <Widget>[ Text( " " + category.name, style: TextStyle(color: Colors.black), ), ], ), ); }).toList(), ), ); }
产品下拉框(无需额外修改)
Widget _prepareProductsDDL() { return Container( width: 350, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(10), boxShadow: [ BoxShadow( color: Color.fromRGBO(225, 95, 27, .3), blurRadius: 20, offset: Offset(0, 10), ), ], ), child: DropdownButton<ProductModel>( hint: Text(" Product"), value: this._selectedProducts, onChanged: (ProductModel value) { setState( () { this._selectedProducts = value; }, ); }, items: this._filteredstoreProdList.map((ProductModel product) { return DropdownMenuItem<ProductModel>( value: product, child: Row( children: <Widget>[ Text( product.name.length > 30 ? " " + product.name.substring(0, 30) : product.name, style: TextStyle(color: Colors.black), ), ], ), ); }).toList(), ), ); }
内容的提问来源于stack exchange,提问作者akshay ramagiri
相关产品推荐
相关产品推荐

