颤动中从孩子到父母的回调

Posted

技术标签:

【中文标题】颤动中从孩子到父母的回调【英文标题】:Callback from child to parent in flutter 【发布时间】:2021-08-04 21:33:43 【问题描述】:

我正在为 e com 应用程序开发购物车页面。后端是firebase实时数据库。在购物车页面价格详细信息正在计算页面加载时。但是当用户更改购物车项目的数量时,它将更新购物车。但问题是这次不能计算价格细节。当我重新打开页面时,价格详细信息正在根据新的购物车数量计算。但是如果不重新打开页面,我怎么能做到这一点

1.这是我的 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.这是 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.之后我需要在购物车页面底部查看计算出的总金额

【问题讨论】:

***.com/questions/67312142/… 【参考方案1】:

更新Cart_products类中的产品数量值:

您需要在Single_cart_product 类中创建一个变量final ValueChanged&lt;int&gt; onProdQty;,然后在数量值更改的地方使用像widget.onProdQty?.call(here Pass the new quantity value) 这样的回调。最后一步是在类Cart_products 中调用Single_cart_product() 将其添加到参数onProdQty: (value) =&gt; setState(() Products_on_the_cart[index].qty = value; ), 中。通过在调用回调时执行此操作,setstate 将在 Cart_products 类中运行,并且无论在何处使用 Products_on_the_cart[index].qty,它都会得到更新。

更新CartPage类中的产品数量值:

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

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

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

),)
然后添加List&lt;CartModel&gt; Products_on_the_cart=List();在 在cart_page.dart 中的_CartPageState 类以及最后在body: Cart_products() 中进行这些更改:
Cart_products(onProdQty: (value) => setState(()
    Products_on_the_cart[index].qty = value; 
),)
现在在底部导航栏中使用Products_on_the_cart[index].qty

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

【讨论】:

非常感谢。这是工作。 !云你请给我一个建议,将总金额发送到 cart_page.dart 中的底部导航栏 我很高兴它对你有用。至于建议,我很快会在答案中分享一个简单的项目,这将帮助您更加熟悉回调。但截至目前,我已经更新了bottomNavigationBar 的答案。不幸的是,我不能保证它会起作用,因为我对您的项目的信息有限。但我相信它会给你这个想法。

以上是关于颤动中从孩子到父母的回调的主要内容,如果未能解决你的问题,请参考以下文章

指定的孩子已经有一个父母。您必须首先在孩子的父母上调用 removeView()。 (C#)

Fragments - 指定的孩子已经有一个父母。您必须先在孩子的父母上调用 removeView()

为啥我无法捕捉到父母发送的孩子的信号?

跳过孩子到父母的获取 - JPA

将孩子添加到父母后是不是必须调用 doLayout() 方法?

将孩子的属性应用到父母