Flutter中如何从列表及UI中永久删除BasketItem?
解决点击删除按钮移除购物车条目并更新UI的问题
你当前代码的核心问题在于列表的不可变性和状态管理的错误传递,下面一步步给你修正:
1. 修复购物车列表的可修改性
你现在的items是全局const列表,const对象无法被修改,调用removeAt会直接报错。把列表移到BasketItemsList的State内部,改成可修改的普通列表:
修改BasketItemsList类:
import 'package:flutter/material.dart'; import 'package:pharmacist_app/Models/basket_item_model.dart'; import 'package:pharmacist_app/widgets/basket_item.dart'; class BasketItemsList extends StatefulWidget { const BasketItemsList({super.key}); @override State<BasketItemsList> createState() => _BasketItemsListState(); } class _BasketItemsListState extends State<BasketItemsList> { // 把列表移到State内部,去掉const,变成可修改列表 List<BasketItemModel> items = [ BasketItemModel( name: 'Paracetamol', price: 2000, image: 'assets/images/download (1).jpeg', amount: 0, counter: 1, ), BasketItemModel( name: 'Paracetamol', price: 10500, image: 'assets/images/download (1).jpeg', amount: 0, counter: 1, ), ]; double sum = 0.0; // 新增删除方法,供子组件调用 void removeItem(int index) { setState(() { items.removeAt(index); }); } @override Widget build(BuildContext context) { return SliverList( delegate: SliverChildBuilderDelegate( childCount: items.length, (context, i) { // 把删除方法传递给BasketItem return BasketItem( item: items[i], index: i, onDelete: () => removeItem(i), ); } ), ); } double sums() { sum = 0.0; // 每次计算前重置,避免累加旧值 for (int i = 0; i < items.length; i++) { sum += items[i].price * items[i].counter; // 乘以数量才是正确的单条总价 } return sum; } }
2. 修改BasketItem,通过回调通知父组件删除
去掉全局的objList和isThereAnItem,改为接收父组件传的删除回调,点击删除按钮时直接调用:
修改BasketItem类:
import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pharmacist_app/Models/basket_item_model.dart'; import 'package:pharmacist_app/controller/basketController.dart'; class BasketItem extends StatefulWidget { const BasketItem({ super.key, required this.item, required this.index, required this.onDelete, // 新增删除回调参数 }); final BasketItemModel item; final int index; final VoidCallback onDelete; @override State<BasketItem> createState() => _BasketItemState(); } class _BasketItemState extends State<BasketItem> { // 每个条目单独维护数量状态 late int _counter; @override void initState() { super.initState(); _counter = widget.item.counter; // 从初始化数据中获取初始数量 } @override Widget build(BuildContext context) { return Column( children: [ Container( padding: const EdgeInsets.only(top: 20), width: double.infinity, height: 120, child: Column( children: [ Row( mainAxisSize: MainAxisSize.min, children: [ // 图片区域保留原逻辑 Padding( padding: const EdgeInsets.only(left: 13.0), child: ClipRRect( borderRadius: const BorderRadius.all(Radius.circular(10)), child: Image.asset( widget.item.image, width: 100, ), ), ), // 商品信息区域保留原逻辑 Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( widget.item.name, style: const TextStyle( fontSize: 18, fontFamily: 'Open Sans', color: Color(0xff003A71), fontWeight: FontWeight.bold, ), ), const SizedBox(height: 20), Text( '${widget.item.price} SR', style: const TextStyle( fontSize: 16, fontFamily: 'Open Sans', color: Color(0xff003A71), fontWeight: FontWeight.w300), ), ], ), ) ], ), const SizedBox(width: 40), // 操作按钮区域修改 Expanded( child: Padding( padding: const EdgeInsets.only(right: 20), child: Container( height: 40, alignment: Alignment.center, decoration: const BoxDecoration( color: Color(0xff88BFDD), borderRadius: BorderRadius.all(Radius.circular(30)), boxShadow: [ BoxShadow( color: Colors.black, offset: Offset(1, 2), blurRadius: 3, ), ], ), child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( onPressed: () { setState(() { _counter++; // 如果用GetX统一管理状态,这里可以调用控制器更新对应条目的数量 // Get.find<BasketController>().updateItemCounter(widget.index, _counter); }); }, icon: const Icon( size: 18, Icons.add, color: Color(0xff003A71), ), ), Text('$_counter'), _counter > 1 ? IconButton( onPressed: () { setState(() { _counter--; }); }, icon: const Icon( size: 18, Icons.remove, color: Color(0xff003A71), ), ) : IconButton( onPressed: widget.onDelete, // 直接调用父组件的删除回调 icon: const Icon( size: 18, Icons.delete, color: Color(0xff003A71), ), ), ], ), ), ), ), ], ), ], ), ), Divider( thickness: 1, color: const Color(0xff013a71).withOpacity(.2), endIndent: 50, indent: 50, ), ], ); } }
3. 额外优化建议(可选)
如果用GetX做状态管理,更规范的做法是把items列表放到BasketController里,统一管理所有购物车操作:
- 在控制器中定义
RxList<BasketItemModel> items = [...].obs; - 添加删除方法:
void removeItem(int index) => items.removeAt(index); - 父组件用
Obx监听列表变化,子组件通过Get.find<BasketController>()调用删除方法
这样可以避免父子组件的回调传递,状态管理更清晰。
内容的提问来源于stack exchange,提问作者Zakaria N
相关产品推荐
相关产品推荐

