Flutter:使用Provider实现商品数量达10时仅触发一次Snackbar的问题
Flutter商品数量选择器SnackBar重复弹出问题修复
问题描述
实现商品数量选择器时遇到以下问题:
- 需求:数量到10后点击「添加」按钮不再改变数量,且仅弹出一次Snackbar,之后不再弹出
- 当前问题:数量达到10后,每次点击「添加」仍会重复弹出Snackbar
现有代码
Provider状态管理类
class QuantitySelector extends ChangeNotifier { final Map<int, int> _quantities = {}; int getQuantityValue(int productId) => _quantities[productId] ?? 1; snackBar(context, int productId) { final currentValue = _quantities[productId] ?? 1; if (currentValue <= 10) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( elevation: 0.0, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), backgroundColor: const Color(0xFF6DBD28), content: Row( children: [ const Icon( Icons.done, color: Colors.white, ), buildSizeBoxWidth(10), Text( AppStrings.kSnackBarText, style: AppStyles.kSnackBarTextStyles, ), ], ), behavior: SnackBarBehavior.floating, dismissDirection: DismissDirection.none, margin: EdgeInsets.only( bottom: MediaQuery.of(context).size.height - 160, ), ), ); } } void quantityIncrement(int productId) { final currentValue = _quantities[productId] ?? 1; if (currentValue < 10) { _quantities[productId] = currentValue + 1; notifyListeners(); } } void quantityDecrement(int productId) { final currentValue = _quantities[productId] ?? 1; if (currentValue > 1) { _quantities[productId] = currentValue - 1; notifyListeners(); } } void resetProductQuantity(int productId) { _quantities.remove(productId); notifyListeners(); } Color quantityIncrementButtonColor(int productId) { final currentValue = _quantities[productId] ?? 1; if (currentValue < 10) { return AppColors.kPrimaryColor; } return AppColors.kGrayColor.withOpacity(0.5); } Color quantityDecrementButtonColor(int productId) { final currentValue = _quantities[productId] ?? 1; if (currentValue > 1) { return AppColors.kPrimaryColor; } return AppColors.kGrayColor.withOpacity(0.5); } }
数量选择器Widget
class ProductQuantitySelectorRow extends StatelessWidget { final int productId; const ProductQuantitySelectorRow({super.key, required this.productId}); @override Widget build(BuildContext context) { final quantitySelector = Provider.of<QuantitySelector>(context); return Row( children: [ ProductQuantitySelector( color: quantitySelector.quantityDecrementButtonColor(productId), margin: const EdgeInsets.only(right: 10), symbol: '-', onTap: () { quantitySelector.quantityDecrement(productId); // showCustom(context); }, ), SizedBox( height: 30, width: 20, child: Center( child: Text( quantitySelector.getQuantityValue(productId).toString(), ), ), ), ProductQuantitySelector( margin: const EdgeInsets.only(left: 10), symbol: '+', color: quantitySelector.quantityIncrementButtonColor(productId), onTap: () { quantitySelector.quantityIncrement(productId); quantitySelector.snackBar(context,productId); }, ) ], ); } }
问题根源
snackBar方法的判断条件currentValue <=10过于宽泛,当数量已经是10时,每次点击都会触发弹出- Widget中每次点击「添加」都会无条件调用
snackBar方法,没有控制触发时机
修复方案
步骤1:添加状态标记控制Snackbar弹出次数
在QuantitySelector类中新增一个Map,记录每个商品是否已经显示过数量上限的Snackbar:
final Map<int, bool> _hasShownMaxSnackbar = {};
步骤2:整合Snackbar触发逻辑到增量方法
将Snackbar的显示逻辑整合到quantityIncrement中,控制仅在数量变化或首次达到上限时弹出:
// 重命名原snackBar方法为私有方法,避免外部随意调用 void _showSnackbar(BuildContext context, int productId) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( elevation: 0.0, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.zero), backgroundColor: const Color(0xFF6DBD28), content: Row( children: [ const Icon( Icons.done, color: Colors.white, ), buildSizeBoxWidth(10), Text( AppStrings.kSnackBarText, style: AppStyles.kSnackBarTextStyles, ), ], ), behavior: SnackBarBehavior.floating, dismissDirection: DismissDirection.none, margin: EdgeInsets.only( bottom: MediaQuery.of(context).size.height - 160, ), ), ); } void quantityIncrement(int productId, BuildContext context) { final currentValue = _quantities[productId] ?? 1; if (currentValue < 10) { _quantities[productId] = currentValue + 1; notifyListeners(); _showSnackbar(context, productId); } else if (currentValue == 10 && !(_hasShownMaxSnackbar[productId] ?? false)) { // 仅首次达到10时弹出Snackbar _showSnackbar(context, productId); _hasShownMaxSnackbar[productId] = true; } }
步骤3:修改Widget的点击逻辑
移除Widget中单独调用snackBar的代码,改为直接调用整合后的增量方法:
onTap: () { quantitySelector.quantityIncrement(productId, context); },
可选:重置状态时清除标记
如果需要支持重置商品数量,在resetProductQuantity方法中同时清除对应的Snackbar标记:
void resetProductQuantity(int productId) { _quantities.remove(productId); _hasShownMaxSnackbar.remove(productId); // 清除标记 notifyListeners(); }
修复后效果
- 数量小于10时,每次点击「添加」都会增加数量并弹出Snackbar
- 数量从9增加到10时,弹出一次Snackbar并标记,后续点击不再弹出
- 数量已达10且已标记后,点击「添加」无任何操作
内容的提问来源于stack exchange,提问作者Martins
相关产品推荐
相关产品推荐

