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

Flutter购物App:如何在CartPage中使用Points变量完成下单

问题描述

开发Flutter测试购物App时,无法在CartPage页面的「order now」按钮的onPressed回调中,使用Points页面内的_points变量来确认购买操作。

现有代码

CartModel

class CartModel extends ChangeNotifier {
  // list of items on sale
  final List _shopItems = const [
    // [ itemName, itemPrice, imagePath, color ]
    ["Avocado", "4", "assets/images/avocado.png", Colors.green],
    ["Banana", "2", "assets/images/banana.png", Colors.yellow],
    ["pollo", "12", "assets/images/chicken.png", Colors.brown],
    ["acqua", "1", "assets/images/water.png", Colors.blue],
    ["mela", "3", "assets/images/mela.png", Colors.red],
    ["broccoli", "3", "assets/images/broccoli.png", Colors.brown],
  ];

  final List _faidate = const [
    ["Avocado", "14000", "assets/images/avocado.png", Colors.orange],
    ["Banana", "2", "assets/images/banana.png", Colors.blueGrey],
    ["pollo", "12", "assets/images/chicken.png", Colors.red],
    ["acqua", "1", "assets/images/water.png", Colors.blue],
  ];

  // list of cart items
  final List _cartItems = [];

  get faidate => _faidate;

  get cartItems => _cartItems;

  get shopItems => _shopItems;
  // add item to cart
  void addItemToCart(int index) {
    _cartItems.add(_shopItems[index]);
    notifyListeners();
  }

  // remove item from cart
  void removeItemFromCart(int index) {
    _cartItems.removeAt(index);
    notifyListeners();
  }

  // calculate total price
  String calculateTotal() {
    double totalPrice = 0;
    for (int i = 0; i < cartItems.length; i++) {
      totalPrice += double.parse(cartItems[i][1].toString());
    }
    return totalPrice.toStringAsFixed(2);
  }
}

CartPage

class CartPage extends StatelessWidget {
  CartPage({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    Device.screenType == ScreenType.tablet;
    return Container(
      width: 100.w,
      height: 90.5.h,
      child: Container(
        width: 100.w,
        height: 20.5.h,
        child: Scaffold(
          appBar: AppBar(
            backgroundColor: Colors.transparent,
            elevation: 0,
            iconTheme: IconThemeData(
              color: Colors.grey[800],
            ),
          ),
          body: Consumer<CartModel>(
            builder: (context, value, child) {
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Padding(
                    padding: EdgeInsets.symmetric(horizontal: 24.0),
                    child: Text(
                      "Cart",
                      style: GoogleFonts.notoSerif(
                        fontSize: 36,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                  ),

                  // list view of cart
                  Expanded(
                    child: Padding(
                      padding: const EdgeInsets.all(12.0),
                      child: ListView.builder(
                        itemCount: (value.cartItems.length),
                        padding: EdgeInsets.all(12),
                        itemBuilder: (context, index) {
                          return Padding(
                            padding: const EdgeInsets.all(12.0),
                            child: Container(
                              decoration: BoxDecoration(
                                  color: Colors.grey[200],
                                  borderRadius: BorderRadius.circular(8)),
                              child: ListTile(
                                leading: Image.asset(
                                  value.cartItems[index][2],
                                  height: 36,
                                ),
                                title: Text(
                                  value.cartItems[index][0],
                                  style: const TextStyle(fontSize: 18),
                                ),
                                subtitle: Text(
                                  '\points ' + value.cartItems[index][1],
                                  style: const TextStyle(fontSize: 12),
                                ),
                                trailing: IconButton(
                                  icon: const Icon(Icons.cancel),
                                  onPressed: () => Provider.of<CartModel>(
                                          context,
                                          listen: false)
                                      .removeItemFromCart(index),
                                ),
                              ),
                            ),
                          );
                        },
                      ),
                    ),
                  ),

                  // total amount + pay now
                  Padding(
                    padding: const EdgeInsets.all(25.0),
                    child: Container(
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(8),
                          color: Colors.blueGrey[900]),
                      padding: const EdgeInsets.all(24),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Text(
                                'total price',
                                style: TextStyle(color: Colors.green[200]),
                              ),
                              const SizedBox(height: 8),
                              Text(
                                '\Points ${value.calculateTotal()}',
                                style: const TextStyle(
                                  fontSize: 18,
                                  fontWeight: FontWeight.bold,
                                  color: Colors.white,
                                ),
                              ),
                            ],
                          ),
                          Container(
                            padding: const EdgeInsets.all(1),
                            child: Row(
                              children: [
                                ElevatedButton(
                                    onPressed: () {},
                                    child: const Text('order now')),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  )
                ],
              );
            },
          ),
        ),
      ),
    );
  }
}

Points页面

class Points extends StatefulWidget {
  Points({Key? key,}) :super(key: key);
  _PointsState createState() => _PointsState();
} 

class _PointsState extends State<Points> {
  int _points = 0;

  @override
  void initState() {
    super.initState();
    _loadPunti();
  }

  _loadPunti() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _points = (prefs.getInt('points') ?? 0);
    });
  }

  _savePunti() async {
    await FirebaseFirestore.instance.collection('xxxx').add({
      'Points': _points,
    });
  }
  // other code...
}
解决方案

核心问题是_points是Points页面的局部状态,无法直接跨页面访问。利用你已有的Provider状态管理方案,把积分状态迁移到全局的CartModel中,就能在CartPage直接调用。

步骤1:扩展CartModel管理积分

修改CartModel,添加积分相关的属性和方法:

class CartModel extends ChangeNotifier {
  // ... 原有代码保持不变 ...

  int _points = 0;

  get points => _points;

  // 加载积分
  Future<void> loadPoints() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    _points = prefs.getInt('points') ?? 0;
    notifyListeners();
  }

  // 保存积分到SharedPreferences和Firebase
  Future<void> savePoints() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setInt('points', _points);
    await FirebaseFirestore.instance.collection('xxxx').add({
      'Points': _points,
    });
    notifyListeners();
  }

  // 扣减积分(购买时调用)
  bool deductPoints(double total) {
    int totalInt = total.toInt();
    if (_points >= totalInt) {
      _points -= totalInt;
      notifyListeners();
      return true;
    }
    return false;
  }
}

步骤2:修改CartPage的按钮逻辑

在order now按钮的onPressed中,获取积分并判断是否足够,处理购买流程:

// 替换原来的ElevatedButton部分
ElevatedButton(
  onPressed: () async {
    // 获取购物车总价
    double total = double.parse(value.calculateTotal());
    // 获取CartModel实例
    final cartModel = Provider.of<CartModel>(context, listen: false);
    
    // 确保积分已加载
    await cartModel.loadPoints();
    
    // 判断积分是否足够
    if (cartModel.deductPoints(total)) {
      // 积分足够,执行购买逻辑(比如清空购物车、保存积分)
      cartModel._cartItems.clear();
      await cartModel.savePoints();
      // 提示用户购买成功
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('购买成功!')),
      );
    } else {
      // 积分不足提示
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('积分不足,无法完成购买')),
      );
    }
  },
  child: const Text('order now')
),

步骤3:更新Points页面使用全局积分

修改Points页面,不再使用局部状态,而是通过Provider获取CartModel的积分:

class Points extends StatelessWidget { // 改为StatelessWidget,状态由CartModel管理
  const Points({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Consumer<CartModel>(
      builder: (context, cartModel, child) {
        return Scaffold(
          // 你的页面UI,直接使用cartModel.points
          body: Center(
            child: Text('当前积分:${cartModel.points}'),
          ),
          // 如果需要更新积分,调用cartModel的方法
          floatingActionButton: FloatingActionButton(
            onPressed: () async {
              cartModel._points += 10; // 示例:增加积分
              await cartModel.savePoints();
            },
            child: const Icon(Icons.add),
          ),
        );
      },
    );
  }
}

额外注意

  • 确保在App启动时,初始化CartModel并加载积分,比如在main.dart中:
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final cartModel = CartModel();
  await cartModel.loadPoints();
  runApp(
    ChangeNotifierProvider.value(
      value: cartModel,
      child: const MyApp(),
    ),
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 23:05:27