You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 09:15:57