Flutter添加按钮需三次点击才生效,请求排查问题
问题分析与修复方案
核心问题根源
对象引用导致的
contains判断失效userOrders.contains(widget.food)是基于对象引用判断相等的,但第一次点击时你添加的是复制出的newFood新对象,和widget.food不是同一个引用。后续判断userOrders.contains(widget.food)会一直返回false,直到第二次手动把widget.food加入列表,第三次点击才会触发增量逻辑。
如果Food和Variation类没重写==和hashCode,即使属性完全相同,不同对象也会被判定为不相等,进一步打乱判断逻辑。状态更新不统一
部分分支调用了setState刷新UI,部分分支仅更新Provider状态却不触发Widget重建,导致数量显示无法及时同步。逻辑分支冗余与状态遗漏
第一次添加新食物时,只把newFood加入订单,却没同步更新FoodCount的计数状态,导致UI显示的数量始终为0,需要多次点击才能触发正确的增量操作。
修复步骤
1. 重写对象相等性判断
给Food和Variation类添加==运算符和hashCode,基于业务唯一标识判断相等性:
class Food { // 原有属性... final String name; final Variation? selectedVar; // 构造函数... @override bool operator ==(Object other) => identical(this, other) || other is Food && runtimeType == other.runtimeType && name == other.name && selectedVar == other.selectedVar; @override int get hashCode => name.hashCode ^ (selectedVar?.hashCode ?? 0); } class Variation { final String imgUrl; final String name; Variation(this.imgUrl, this.name); @override bool operator ==(Object other) => identical(this, other) || other is Variation && runtimeType == other.runtimeType && imgUrl == other.imgUrl && name == other.name; @override int get hashCode => imgUrl.hashCode ^ name.hashCode; }
2. 简化+按钮逻辑,统一状态更新
删除冗余分支,确保每次操作都正确更新计数和UI:
GestureDetector( onTap: () { if (widget.food.selectedVar == null) { errorDialog(context, 'ERROR', 'Please select a variation'); return; } // 检查订单中是否已有同款食物(基于属性相等) final hasExisting = userOrders.any((food) => food == widget.food); if (hasExisting) { // 已有同款,直接增量 context.read<FoodCount>().increment(widget.food); } else { // 无同款,添加并初始化计数为1 userOrders.add(widget.food); context.read<FoodCount>().setCount(widget.food, 1); } // 统一更新全局计数器并刷新UI context.read<Counter>().update(); setState(() {}); }, child: const Text( '+', style: TextStyle( fontSize: 30, fontWeight: FontWeight.bold, color: Colors.white38, ), ), )
3. 完善FoodCount Provider方法
给FoodCount添加初始化计数的方法:
class FoodCount extends ChangeNotifier { final Map<Food, int> _counts = {}; int display(Food food) => _counts[food] ?? 0; void increment(Food food) { _counts[food] = (display(food) + 1); notifyListeners(); } void decrement(Food food) { if (display(food) > 0) { _counts[food] = (display(food) - 1); notifyListeners(); } } // 添加初始化计数方法 void setCount(Food food, int count) { _counts[food] = count; notifyListeners(); } }
4. 移除冗余的selectedVars列表
如果selectedVars仅用于判断变体是否选中,直接通过widget.food.selectedVar != null判断即可,无需维护额外列表,减少状态冗余。
额外优化建议
- 不要直接操作全局的
userOrders列表,建议将其放入Provider中管理,确保状态变更可追踪、一致。 - 简化多层嵌套的if-else逻辑,使用提前return减少嵌套深度,提升代码可读性。
内容的提问来源于stack exchange,提问作者shimomaru
相关产品推荐
相关产品推荐

