从 child 回调到 parent in flutter

Callback from child to parent in flutter

我正在为电子商务应用程序开发购物车页面。后端是 firebase 实时数据库。在购物车页面中,页面价格详细信息在页面加载时计算。但是当用户更改购物车商品的数量时,它将更新购物车。但问题是这次无法计算价格细节。当我重新打开页面时,价格详情正在根据新的购物车数量计算。但是我怎样才能做到这一点而不重新打开页面

1.This 是我的 cart_page.dart 文件

  //this cart is show when user select my cart From the navigation drawer
import 'package:flutter/material.dart';
import 'package:buy_app_flutter/main.dart';
import 'package:buy_app_flutter/pages/notification_page.dart';
import 'package:buy_app_flutter/pages/search_page.dart';
import 'package:buy_app_flutter/componets/cart_products.dart';

import 'BuyNowDeliveryDetailsPage.dart';
import 'HomePage.dart';

class CartPage extends StatefulWidget {
  @override
  _CartPageState createState() => _CartPageState();
}

class _CartPageState extends State<CartPage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(

      drawer: new DrawerCodeOnly(),

      appBar: new AppBar(
        elevation: 0.1,
        backgroundColor: Colors.orangeAccent,
        title: Text("My Cart"),
        actions:<Widget> [
          new IconButton(icon: Icon(Icons.search,color: Colors.white,), onPressed: (){
            showSearch(context: context, delegate: DataSearch());
          } ),

          new IconButton(icon: Icon(Icons.notifications,color: Colors.white,), onPressed: (){
            Navigator.push(context, MaterialPageRoute(builder: (context) => new NotificationPage() ));
          } ),

        ],
      ),

      body:new Cart_products(),

      bottomNavigationBar:new Container(
        color: Colors.white,
        child: Row(
          children:<Widget> [
            Expanded(child: ListTile(
              title: new Text("Total:"),
              subtitle:new Text("Rs 00.00") ,
            )),

            Expanded(
                child: new MaterialButton(onPressed: (){
                  Navigator.push(context, MaterialPageRoute(builder: (context) => new BuyNowDeliveryDetailsActivity() ));
                },
                  child: new Text("Check Out"),
                  color: Colors.orangeAccent,
                )
            )

          ],
        ),
      ) ,
    );
  }
}

2.This 是 cart_procucts.dart 文件

import 'package:buy_app_flutter/DBModels/CartModel.dart';
import 'package:buy_app_flutter/DBModels/ProductModel.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';

class Cart_products extends StatefulWidget {
  @override
  _Cart_productsState createState() => _Cart_productsState();
}

class _Cart_productsState extends State<Cart_products> {

  //firebase database reference to cart===============================
  final Cartref= FirebaseDatabase.instance.reference().child("UserData").child(FirebaseAuth.instance.currentUser.uid).child("Cart");

  List<CartModel> Products_on_the_cart=List();
  ///=============================================firebase end
  bool _progressController=true;

  //variables to cal total
  int TotalItemPrice=0;
  int SavedAmount=0;
  int DeliveryPrice=0;
  int TotalAmount=0;

  @override
  initState(){
    _getCartList();  //call function to get cart from firebase
    super.initState();
  }

  ///display the cart Items one by one===============================
  @override
  Widget build(BuildContext context) {

    if(_progressController==true) //reading database
        {
      return Center(child: new CircularProgressIndicator());
    }
    else{  //db read end=========
          if(Products_on_the_cart.isNotEmpty)
            {
              _calTotalPrice();
              //===============================================if not empty the cart

              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  ListView.separated(
                    itemBuilder: (context, index){
                        return Single_cart_product(
                        cart_product_key: Products_on_the_cart[index].productKey,
                        cart_product_name: Products_on_the_cart[index].ProductTitle,
                        cart_prod_picture: Products_on_the_cart[index].Img,
                        cart_prod_price: Products_on_the_cart[index].Price,
                        cart_prod_cutted_price: Products_on_the_cart[index].CuttedPrice,
                        cart_prod_qty: Products_on_the_cart[index].qty,
                        cart_product_status: Products_on_the_cart[index].Status,

                        );
              },
                    //end of item builder
                    separatorBuilder:(context,index){
                      return Row();
                    },
                    itemCount: Products_on_the_cart.length,
                    shrinkWrap: true,

                  ),

                  Divider(),

                  Padding(
                    padding: const EdgeInsets.only(left: 8.0),
                    child: Text("PRICE DETAILS",style: TextStyle(fontWeight: FontWeight.bold,color: Colors.grey),),
                  ),

                  Divider(),

                  ///start of items total price row===========================
                  Padding(
                    padding: const EdgeInsets.only(left: 8.0,right: 8.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text("price (${Products_on_the_cart.length} items)",style: TextStyle(fontWeight: FontWeight.normal,color: Colors.black),),

                        Text("Rs ${TotalItemPrice}/-",style: TextStyle(fontWeight: FontWeight.normal,color: Colors.black),),
                      ],
                    ),
                  ),
                  ///end of items total price row============================

                  ///start of delivery price row==================================
                  Padding(
                    padding: const EdgeInsets.only(left: 8.0,top: 8.0,right: 8.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text("Delivery",style: TextStyle(fontWeight: FontWeight.normal,color: Colors.black),),

                        Text("Rs ${DeliveryPrice}/-",style: TextStyle(fontWeight: FontWeight.normal,color: Colors.green),),
                      ],
                    ),
                  ),
                  ///end of delivery price row============================

                  Divider(),

                  ///Start of total amount row==================================
                  Padding(
                    padding: const EdgeInsets.only(left: 8.0,right: 8.0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceBetween,
                      children: [
                        Text("Total Amount",style: TextStyle(fontWeight: FontWeight.bold,color: Colors.black),),

                        Text("Rs ${TotalAmount}/-",style: TextStyle(fontWeight: FontWeight.bold,color: Colors.black),),
                      ],
                    ),
                  ),
                  ///end of total amount row===========================================

                  Divider(),

                  Padding(
                    padding: const EdgeInsets.only(left: 8.0,right: 8.0),
                    child: Text("You saved Rs ${SavedAmount}/- on this order",style: TextStyle(fontWeight: FontWeight.normal,color: Colors.green),),
                  ),

                ],
              );

              //end of if not empty the cart===========================================
            }
          else
            {
              return Center(child: Text("Your cart is empty !"));
            }
    }


  }

  ///end of displaying cart items one by one====================================

  _getCartList()
  async {

    //get cart data from firebase==========

    try{
      await Cartref.once().then((DataSnapshot snapshot) {
        var data = snapshot.value;

        if(data==null)  //if the no cart items found hide progress
            {
          setState(() {
            _progressController=false;
          });
        }

        Products_on_the_cart.clear();

        data.forEach((key,value)
        async {
          CartModel model = new CartModel(

            date: value["date"],
            time: value["time"],
            productKey: value["productKey"],
            qty: value["qty"],

          );

          //use  Pref(product ref) to get details from products record

          try{

            //Product details ref and list
            final Pref= FirebaseDatabase.instance.reference().child("Product");

            List<ProductModel> product =List();

            //====================================
            await Pref.child(model.productKey).once().then((DataSnapshot snap) {

              // print('Product : ${snap.value}');
              model.ProductTitle=snap.value["ProductTitle"];
              model.Img=snap.value["img1"];
              model.Price=snap.value["Price"];
              model.DPrice=snap.value["DPrice"];
              model.CuttedPrice=snap.value["CuttedPrice"];
              model.Status=snap.value["Status"];

            });

          }
          catch(e)
          {
            print("Error In try block for get data from real time db ");
            print(e);
          }
          finally
              {
                setState(() {
                  _progressController=false;
                });
              }

          //========================================================end of get product details

          setState(() {
            Products_on_the_cart.add(model);
          });

        }
        );

      });
    }
    catch(e)
    {
      print(e);
    }

    // end of get cart data from firebase
  }

  ///function for calculate total price
  _calTotalPrice(){

     TotalItemPrice=0;
     DeliveryPrice=0;
     TotalAmount=0;
     SavedAmount=0;

    Products_on_the_cart.forEach((item){

      //set total item price===========
         TotalItemPrice=TotalItemPrice+int.parse(item.Price)*int.parse(item.qty);

         //set delivery price==========
         if (item.DPrice=="FREE")
         {
           //nothing
         }
         else
         {

           if (int.parse(item.DPrice)>DeliveryPrice)
           {
             DeliveryPrice=int.parse(item.DPrice);
           }
         }

         //set Total amount=======
        TotalAmount=TotalItemPrice+DeliveryPrice;

         //set saved amount
         SavedAmount=SavedAmount + (int.parse(item.CuttedPrice)-int.parse(item.Price))*int.parse(item.qty);
         
    });
  }
  /// end of calculate total price function

}


///from here design the cart item display ==========================================
class Single_cart_product extends StatefulWidget {

  final cart_product_key;
  final cart_product_name;
  final cart_prod_picture;
  final cart_prod_price;
  final cart_prod_cutted_price;
  String cart_prod_qty;
  final cart_product_status;

  Single_cart_product({
    this.cart_product_key,
    this.cart_product_name,
    this.cart_prod_picture,
    this.cart_prod_price,
    this.cart_prod_cutted_price,
    this.cart_prod_qty,
    this.cart_product_status,
});

  @override
  _Single_cart_productState createState() => _Single_cart_productState();
}

class _Single_cart_productState extends State<Single_cart_product> {
  ///==========================start of Cart Item Display Design==================================================================
  @override
  Widget build(BuildContext context) {

    var cartQty=int.parse(widget.cart_prod_qty);

    return Card(
      child: Column(
        children: [
          ListTile(
            ///===============START LEADING SECTION ===============================
            leading: FadeInImage.assetNetwork(
              placeholder: 'assets/close_box.png',
              image:widget.cart_prod_picture,
              height: 80.0,
              width: 80.0,
              fit: BoxFit.contain,
            ),
            ///=======END OF LEADING SECTION=======================================

            /// =========== TITLE SECTION =========================================
            title: new Text(widget.cart_product_name),
            ///====END OF TITLE SECTION============================================

            ///========== SUBTITLE SECTION ==================================
            subtitle: new Column(
              children:<Widget> [
                //Row inside the column
                new Row(
                  children: <Widget> [

                    // =============this section is for the Product price =====
                    new Container(
                      alignment: Alignment.topLeft,
                      child: new Text("\Rs.${widget.cart_prod_price}",
                        style: TextStyle(
                            fontSize:16.0,
                            fontWeight: FontWeight.bold,
                            color: Colors.black
                        ),
                      ),
                    ),

                    SizedBox(width: 4,),
                    //==========this section is for the cutted price of the product=========
                    Padding(
                      padding: const EdgeInsets.all(5.0),
                      child: new Text("\Rs.${widget.cart_prod_cutted_price}",
                        style: TextStyle(
                            fontSize:16.0,
                            fontWeight: FontWeight.normal,
                            decoration: TextDecoration.lineThrough,
                            color: Colors.grey
                        ),
                      ),
                    ),
                    //end of cutted price of the product


                  ],
                ),




              ],
            ),

            ///=====END OF SUBTITLE SECTION============================================

            ///======START OF TRAILING SECTION==========================================

            trailing:
            Column(

              children:
              <Widget>[

                Expanded(child: new IconButton(
                    padding: const EdgeInsets.all(0.0),
                    icon: Icon(Icons.arrow_drop_up), onPressed: (){
                      cartQty++;
                      print(cartQty);
                      _updateCartQty(widget.cart_product_key,cartQty.toString()); //call to update cart qty

                      setState(() {
                        widget.cart_prod_qty=cartQty.toString();
                      });


                })),
                Padding(
                  padding: const EdgeInsets.all(0.0),
                  child: new Text(cartQty.toString()),
                ),
                Expanded(child: new IconButton(
                    padding: const EdgeInsets.all(0.0),
                    icon: Icon(Icons.arrow_drop_down), onPressed: (){
                      if(cartQty>1)
                        {
                          cartQty--;
                          print(cartQty);
                          _updateCartQty(widget.cart_product_key,cartQty.toString()); //call to update cart qty

                          setState(() {
                            widget.cart_prod_qty=cartQty.toString();
                          });
                        }

                })),


              ],
            ),


          ///==END OF TRAILING======================================================================

          ),

          //REMOVE BTN AND STATUS
          Row(
            children: [
              new IconButton(
                  icon: Icon(Icons.delete),
                  color:Colors.red ,
                  onPressed: (){}),

              Padding(
                padding: const EdgeInsets.all(4.0),
                child: new Text(widget.cart_product_status,style: TextStyle(color: Colors.orangeAccent)),
              ),
            ],
          )

          //END OF REMOVE BTN SND STATUS


        ],
      ),



    );
  }

  ///==========================end of Cart Item Display Design==================================================================

  /// function for update cart qty
  _updateCartQty(String Pkey,String Qty){

    try {
      final Cartref = FirebaseDatabase.instance.reference()
          .child("UserData")
          .child(FirebaseAuth.instance.currentUser.uid)
          .child("Cart");

        Cartref.child(Pkey).child("qty").set(Qty);
    }
    catch(Ex)
    {
      Fluttertoast.showToast(
          msg: Ex.message,
          toastLength: Toast.LENGTH_SHORT,
          gravity: ToastGravity.BOTTOM,
          timeInSecForIosWeb: 1,
          backgroundColor: Colors.red,
          textColor: Colors.white,
          fontSize: 16.0);
    }

  }
}

3.After 我需要在购物车页面底部查看计算的总金额

正在更新 Cart_products 中的产品数量值 class:

您需要在 Single_cart_product class 中创建一个变量 final ValueChanged<int> onProdQty;,然后在数量值发生变化的地方使用这样的回调 widget.onProdQty?.call(here Pass the new quantity value)。最后一步是在 class Cart_products 调用 Single_cart_product() 的地方将其添加到参数 onProdQty: (value) => setState(() { Products_on_the_cart[index].qty = value; }), 中。通过在调用回调时执行此操作,setstate 将在 Cart_products class 中 运行 并且在任何使用 Products_on_the_cart[index].qty 的地方都会更新。

正在更新 CartPage 中的产品数量值 class:

注意:我不确定这些步骤是否能正常工作,因为我对您的项目的了解有限。但是您肯定会学习如何使用回调传递数据:

  • 按照 Cart_products 中更新产品数量值的步骤进行操作 class 然后继续。
  • Cart_products中添加final ValueChanged<int> onProdQty; class和 然后在 class Cart_products 中更改 Single_cart_product() 参数 像这样:
Single_cart_product(onProdQty: (value) => setState((){
    Products_on_the_cart[index].qty = value; 

    widget.onProdQty?.call(value); //add this

}),)
  • 然后添加List<CartModel> Products_on_the_cart=List();_CartPageState class 在 cart_page.dart 中,最后在 body: Cart_products() 中进行以下更改:
Cart_products(onProdQty: (value) => setState((){
    Products_on_the_cart[index].qty = value; 
}),)
  • 现在在 bottomNavigationBar 中使用 Products_on_the_cart[index].qty

如果您有任何疑问,请告诉我。