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

Flutter购物车数量计数器失效问题求助

问题描述

我正在使用Flutter开发电商APP,刚接触该框架,借助ChatGPT实现了购物车功能。目前其他功能正常,但数量计数器无法工作,点击+或-按钮均无反应,使用GetX进行状态管理。

购物车页面代码

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:exclusive_details_and_restorations/const/cart_controller.dart';
import 'package:exclusive_details_and_restorations/const/text.dart';

class CartScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CartController cartController = Get.find<CartController>();
    print('CartScreen rebuilt');
    return Container(
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topLeft,
          end: Alignment.bottomRight,
          colors: [
            const Color.fromRGBO(0, 40, 70, 100),
            Colors.red.shade900,
          ],
        ),
      ),
      child: Scaffold(
        backgroundColor: const Color.fromRGBO(0, 40, 70, 100),
        appBar: AppBar(
          iconTheme: const IconThemeData(color: Colors.white),
          backgroundColor: const Color.fromRGBO(0, 40, 70, 100),
          title: const CustomText(
            text: "Cart",
            color: Colors.white,
          ),
          actions: [
            SizedBox(
              width: 100,
              child: Image.asset("assets/images/exclusive-details-rename.png"),
            ),
          ],
        ),
        body: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Obx(
            () => Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Expanded(
                  child: ListView.builder(
                    itemCount: cartController.cartItems.length,
                    itemBuilder: (context, index) {
                      var item = cartController.cartItems[index];
                      return ListTile(
                        title: CustomText(text: item.productName),
                        subtitle: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            CustomText(text: "\$${item.price}"),
                            Row(
                              children: [
                                ElevatedButton(
                                  onPressed: () {
                                    // Decrease quantity
                                    cartController.decreaseQuantity(item);
                                    cartController.update();
                                  },
                                  child: const Icon(Icons.remove),
                                ),
                                Padding(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 8.0),
                                  child: CustomText(
                                      text: item.quantity.toString()),
                                ),
                                ElevatedButton(
                                  onPressed: () {
                                    // Increase quantity
                                    item.increaseQuantity();
                                    cartController.update();
                                  },
                                  child: const Icon(Icons.add),
                                ),
                              ],
                            ),
                          ],
                        ),
                      );
                    },
                  ),
                ),
                const Divider(),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    CustomText(
                      text: "Total: ",
                      size: 18,
                      fontWeight: FontWeight.bold,
                    ),
                    CustomText(
                      text:
                          "\$${cartController.totalAmount.toStringAsFixed(2)}",
                      size: 18,
                      fontWeight: FontWeight.bold,
                    ),
                  ],
                ),
                const SizedBox(height: 20),
                ElevatedButton(
                  onPressed: () {
                    // Implement the checkout logic here
                  },
                  child: const Padding(
                    padding: EdgeInsets.all(8.0),
                    child: CustomText(
                      text: "Proceed to Checkout",
                      size: 16,
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

购物车控制器代码

// controllers/cart_controller.dart
import 'package:exclusive_details_and_restorations/models/cart_model.dart';
import 'package:get/get.dart';

class CartController extends GetxController {
  RxList<CartItem> cartItems = <CartItem>[].obs;

  void addItem(CartItem newItem) {
    int existingIndex = cartItems.indexWhere(
      (item) => item.productName == newItem.productName,
    );

    if (existingIndex != -1) {
      cartItems[existingIndex].quantity += 1;
    } else {
      cartItems.add(newItem);
    }
  }

  void decreaseQuantity(CartItem item) {
    if (item.quantity > 1) {
      item.quantity -= 1;
    } else {
      cartItems.remove(item);
    }
  }

  void clearCart() {
    cartItems.clear();
  }

  double get totalAmount {
    return cartItems.fold(0, (sum, item) => sum + item.totalPrice);
  }
}

购物车模型代码

// models/cart_model.dart
class CartItem {
  final String productId;
  final String productName;
  final double price;
  int quantity;

  CartItem({
    required this.productId,
    required this.productName,
    required this.price,
    required this.quantity,
  });

  double get totalPrice => price * quantity;

  void increaseQuantity() {
    quantity += 1;
  }

  void decreaseQuantity() {
    if (quantity > 1) {
      quantity--;
    }
  }
}

主文件代码

// main.dart
import 'package:exclusive_details_and_restorations/const/cart_controller.dart';
import 'package:exclusive_details_and_restorations/views/about_view.dart';
import 'package:exclusive_details_and_restorations/views/cart_view.dart';
import 'package:exclusive_details_and_restorations/views/gallery_view.dart';
import 'package:exclusive_details_and_restorations/views/home_view.dart';
import 'package:exclusive_details_and_restorations/views/service_areas.dart';
import 'package:exclusive_details_and_restorations/views/services.dart';
import 'package:exclusive_details_and_restorations/views/shop.dart';
import 'package:exclusive_details_and_restorations/views/splash.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      initialBinding: BindingsBuilder(() {
        Get.put(CartController());
      }),
      routes: {
        '/': (context) => const SplashScreen(),
        'home': (context) => const HomeScreen(),
        'about': (context) => const AboutView(),
        'serviceAreas': (context) => const ServiceAreasView(),
        'gallery': (context) => const GalleryView(),
        'services': (context) => const ServicesView(),
        'shop': (context) => EcommerceTest(),
        'cart': (context) => CartScreen(),
      },
    );
  }
}
问题原因

核心问题是GetX的Obx仅监听Rx对象的顶层变化:

  1. cartItems是RxList<CartItem>,但CartItem的quantity是普通int类型,直接修改quantity不会触发RxList的更新通知。
  2. 你调用的cartController.update()是用于GetBuilder的刷新方法,Obx不响应该调用,所以界面不会重新渲染。
解决方案

提供两种可行方案,任选其一即可:

方案一:将CartItem的quantity改为响应式类型

修改cart_model.dart,把quantity改为RxInt,让属性变化能被GetX监听:

import 'package:get/get.dart';

class CartItem {
  final String productId;
  final String productName;
  final double price;
  RxInt quantity;

  CartItem({
    required this.productId,
    required this.productName,
    required this.price,
    required int quantity,
  }) : quantity = quantity.obs;

  double get totalPrice => price * quantity.value;

  void increaseQuantity() {
    quantity.value += 1;
  }

  void decreaseQuantity() {
    if (quantity.value > 1) {
      quantity.value--;
    }
  }
}

同时修改CartScreen中显示数量的代码,读取RxInt的value:

CustomText(text: item.quantity.value.toString()),

删除按钮点击事件里的cartController.update(),因为属性变化会自动触发Obx刷新。

方案二:通过替换列表元素触发RxList更新

修改CartController的方法,通过替换元素让RxList感知到变化,同时给控制器增加increaseQuantity方法:

class CartController extends GetxController {
  RxList<CartItem> cartItems = <CartItem>[].obs;

  void addItem(CartItem newItem) {
    int existingIndex = cartItems.indexWhere(
      (item) => item.productName == newItem.productName,
    );

    if (existingIndex != -1) {
      // 取出原元素、修改后替换回去
      CartItem updatedItem = cartItems[existingIndex];
      updatedItem.quantity += 1;
      cartItems[existingIndex] = updatedItem;
    } else {
      cartItems.add(newItem);
    }
  }

  void increaseQuantity(CartItem item) {
    int index = cartItems.indexOf(item);
    if (index != -1) {
      CartItem updatedItem = cartItems[index];
      updatedItem.quantity += 1;
      cartItems[index] = updatedItem;
    }
  }

  void decreaseQuantity(CartItem item) {
    int index = cartItems.indexOf(item);
    if (index != -1) {
      if (item.quantity > 1) {
        CartItem updatedItem = cartItems[index];
        updatedItem.quantity -= 1;
        cartItems[index] = updatedItem;
      } else {
        cartItems.remove(item);
      }
    }
  }

  void clearCart() {
    cartItems.clear();
  }

  double get totalAmount {
    return cartItems.fold(0, (sum, item) => sum + item.totalPrice);
  }
}

然后修改CartScreen的按钮点击事件:

// 减号按钮
ElevatedButton(
  onPressed: () {
    cartController.decreaseQuantity(item);
  },
  child: const Icon(Icons.remove),
),
// 加号按钮
ElevatedButton(
  onPressed: () {
    cartController.increaseQuantity(item);
  },
  child: const Icon(Icons.add),
),

同样删除cartController.update()调用,因为RxList元素替换会自动触发Obx刷新。

内容的提问来源于stack exchange,提问作者Mohsin Memon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:58:12