简体   繁体   中英

How to change a bottom navigation bar icon in the setState() function in flutter?

I'm building a food ordering app in flutter. What I want is, when the user adds items to the cart, I want the cart icon in the bottom navigation bar to obtain a red dot on top to notify the user of the addition of items to the cart.

To achieve this, I have created a global variable called no_of_cart_items and when the user adds an item to the cart, I increment this variable in the setState() function as follows:

setState(() {
  GlobalVariables.no_of_cart_items+=1;
  // change icon here
});

In this setState() function, I wish to change the icon in the bottom navigation bar. How should I do this? Thank you.

FULL CODE

This is main.dart

//import lines
void main() => runApp(CanteenApp());

class CanteenApp extends StatefulWidget {
  @override
  _CanteenAppState createState() => _CanteenAppState();
}

class _CanteenAppState extends State<CanteenApp> {
  int _currentindex=0; // index of bottom tab

  int admin=GlobalVariables.admin;

  BottomNavigationBadge badger = new BottomNavigationBadge(
    backgroundColor: Colors.red,
    badgeShape: BottomNavigationBadgeShape.circle,
    textColor: Colors.white,
    position: BottomNavigationBadgePosition.topRight,
    textSize: 8);

  Widget callpage(int currentIndex)  {
     switch (currentIndex) {
      case 0: return UserProfile();
      case 1: return Menu();
      case 2: return Cart();
      break;
      default: return UserProfile();
    }
  }
  @override
  Widget build(BuildContext context) {
    if(admin==1 && _currentindex==2) {
      //if you're the admin and have called the history page
      return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: DefaultTabController(
          length: 2,
          child: Scaffold(
            resizeToAvoidBottomPadding: false,
            appBar: PreferredSize(
              preferredSize: Size.fromHeight(80.0),
              child: AppBar(
                bottom: TabBar(
                  indicatorColor: Colors.white,
                  indicatorWeight: 5,
                  tabs: <Widget>[
                    Tab(
                        child: Align(
                            alignment: Alignment.center,
                            child: Text(
                              'Order History',
                              style: TextStyle(
                                  fontSize: 20
                              ),
                            )
                        )
                    ),
                    Tab(
                        child: Align(
                            alignment: Alignment.center,
                            child: Text(
                              'Deposit / Withdraw\nHistory',
                              style: TextStyle(
                                  fontSize: 17
                              ),
                              textAlign: TextAlign.center,
                            )
                        )
                    ),
                  ],
                ),
              ),
            ),
            body: TabBarView(
              children: <Widget>[
                AdminOrderHistory(),
                DepositWithdrawHistory()
              ],
            ),
            bottomNavigationBar: BottomNavigationBar(
                elevation: 10,
                currentIndex: _currentindex,
                items: [
                  BottomNavigationBarItem(
                    icon: Icon(Icons.account_circle),
                    title: Text('Profile'),
                  ),
                  BottomNavigationBarItem(
                    icon: Icon(Icons.restaurant_menu),
                    title: Text('Menu'),
                  ),
                  BottomNavigationBarItem(
                    icon: Icon(Icons.history),
                    title: Text('History'),
                  ),
                ],
                onTap: (index){
                  setState(() {
                    _currentindex=index;
                  });
                }
            ),
          ),
        ),
        theme: appTheme,
      );
    }
    else if(admin==1){
      return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          resizeToAvoidBottomPadding: false,
          body: callpage(_currentindex),
          bottomNavigationBar: BottomNavigationBar(
              elevation: 10,
              currentIndex: _currentindex,
              items: [
                BottomNavigationBarItem(
                  icon: Icon(Icons.account_circle),
                  title: Text('Profile'),
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.restaurant_menu),
                  title: Text('Menu'),
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.history),
                  title: Text('History'),
                ),
              ],
              onTap: (index){
                setState(() {
                  _currentindex=index;
                });
              }
          ),
        ),
        theme: appTheme,
      );
    }
    else if(admin==0){
      return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          resizeToAvoidBottomPadding: false,
          body: callpage(_currentindex),
          bottomNavigationBar:BottomNavigationBar(
              elevation: 10,
              currentIndex: _currentindex,
              items: [
                BottomNavigationBarItem(
                  icon: Icon(Icons.account_circle),
                  title: Text('Profile'),
                ),
                BottomNavigationBarItem(
                  icon: Icon(Icons.restaurant_menu),
                  title: Text('Menu'),
                ),
                BottomNavigationBarItem(
                  title: Text('Cart'),
                  icon: Badge(
                    showBadge: true,
                    badgeContent: Text(
                      GlobalVariables.no_of_cart_items.toString(),
                      style: TextStyle(
                        color: Colors.white
                      ),
                    ),
                    child: Icon(Icons.shopping_cart)
                  )
                ),
              ],
              onTap: (index){
                  setState(() {
                    _currentindex=index;
                  });
              }
          ),
        ),
        theme: appTheme,
      );
    }
  }
}

This is menu.dart

//import lines

int admin=GlobalVariables.admin;

List snacksmenuitems=[
  ['Vada Pav', 15],
  ['Samosa Pav', 15],
  ['Punjabi Samosa', 25],
  ['Pav', 5]
];

List ricemenuitems=[
  ['Fried Rice', 62],
  ['Schezwan Rice', 69],
  ['Singapore Rice', 69],
  ['Manchow Rice', 73],
];

class Menu extends StatefulWidget {
  @override
  _MenuState createState() => _MenuState();
}

class _MenuState extends State<Menu> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        MenuTopPart(),
        MenuBottomPart(),
      ],
    );
  }
}

Color firstColor = Color(0xFFF47D15);
Color secondColor = Color(0xFFEF772C);

class MenuTopPart extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        ClipPath(
            clipper: CustomShapeClipper(),
            child: Container(
                height:140.0,
                width:MediaQuery.of(context).size.width,
                decoration: BoxDecoration(
                    gradient: LinearGradient(
                      colors: [firstColor, secondColor],
                    )
                ),
                child: Column(
                  children: <Widget>[
                    SizedBox(height: 53.0),
                    Text(
                      'MENU',
                      style: TextStyle(
                        fontSize: 30.0,
                        color: Colors.white,
                      ),
                      textAlign: TextAlign.center,
                    ),
                  ],
                )
            )
        )
      ],
    );
  }
}

class MenuBottomPart extends StatefulWidget {
  @override
  _MenuBottomPartState createState() => _MenuBottomPartState();
}

class _MenuBottomPartState extends State<MenuBottomPart> {
  @override
  Widget build(BuildContext context) {
    return Column(
        children: <Widget>[
          SizedBox(height: 10),          
          SizedBox(height: 10),
          Padding(
            padding: const EdgeInsets.fromLTRB(20, 0, 20, 10),
            child: Container(
              height: MediaQuery
                  .of(context)
                  .size
                  .height * 0.60,
              child: ListView(
                padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
                scrollDirection: Axis.vertical,
                children:  <Widget>[
                  Card(
                    child: Padding(
                      padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
                      child: ExpansionTile(
                        title: Text('SNACKS'),
                        children: snacksmenuitems.map((menuitem) {
                          //print(menuitem);
                          return MenuItem(menuitem: menuitem);
                          /*SizedBox(height:10),
                          MenuItem(),
                          SizedBox(height:10),
                          MenuItem(),
                          SizedBox(height:10),
                          MenuItem()*/
                          }).toList()
                      ),
                    )
                  ),
                  SizedBox(height: 10),
                  Card(
                      child: Padding(
                        padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
                        child: ExpansionTile(
                            title: Text('RICE ITEMS'),
                            children: ricemenuitems.map((menuitem) {
                              //print(menuitem);
                              return MenuItem(menuitem: menuitem);
                              /*SizedBox(height:10),
                          MenuItem(),
                          SizedBox(height:10),
                          MenuItem(),
                          SizedBox(height:10),
                          MenuItem()*/
                            }).toList()
                        ),
                      )
                  )
                ]
              ),
            ),
          )
        ]
    );
  }
}

class MenuItem extends StatefulWidget {

  List menuitem=[];
  MenuItem({Key key, this.menuitem}): super(key: key);

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

class _MenuItemState extends State<MenuItem> {

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(bottom: 10),
      decoration: BoxDecoration(
          border: Border.all(color: Colors.black12),
          borderRadius: BorderRadius.all(Radius.circular(10))
      ),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Image(
              image: NetworkImage('https://www.whiskaffair.com/wp-content/uploads/2018/08/Mumbai-Pav-Bhaji-4.jpg'),
              width: 80,
              height: 80
          ),
          SizedBox(width:10),
          Padding(
            padding: const EdgeInsets.fromLTRB(0, 5, 0, 0),
            child: Container(
              width:190,
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  Text(
                    widget.menuitem[0],
                    style: TextStyle(
                        fontSize:19,
                        color: Colors.grey[900]
                    ),
                  ),
                  SizedBox(height:5.0),
                  Padding(
                    padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
                    child: Row(
                      children: <Widget>[
                        Row(
                          children: <Widget>[
                            Text(
                              '₹',
                              style: TextStyle(
                                  fontSize: 15,
                                  color: Colors.grey[800]
                              ),
                            ),
                            Text(
                              widget.menuitem[1].toString(),
                              style: TextStyle(
                                fontSize: 15,
                                color: Colors.grey[800]
                              ),
                            )
                          ],
                        ),
                        SizedBox(width:70),
                        Container(
                            child: Row(
                              children: <Widget>[
                                SizedBox(
                                  width:30,
                                  height:30,
                                  child: FloatingActionButton(
                                    onPressed: (){
                                      setState(() {
                                        if(GlobalVariables.allcartitems[widget.menuitem[0]][0]>0){
                                          GlobalVariables.no_of_cart_items-=1;
                                          GlobalVariables.allcartitems[widget.menuitem[0]][0]-=1;
                                          GlobalVariables.totalcost-=GlobalVariables.allcartitems[widget.menuitem[0]][1];
                                          // CHECK IF CART HAS NO ITEMS AND REMOVE BADGE HERE
                                        }
                                      });
                                    },
                                    elevation: 1,
                                    child: Icon(Icons.remove, size: 18),
                                    backgroundColor: Colors.red[300],
                                    mini: true,
                                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))),
                                  ),
                                ),
                                Padding(
                                  padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
                                  child: Text(
                                    GlobalVariables.allcartitems[widget.menuitem[0]][0].toString(),
                                    style: TextStyle(
                                        fontSize: 18
                                    ),
                                  ),
                                ),
                                SizedBox(
                                  width:30,
                                  height:30,
                                  child: FloatingActionButton(
                                    onPressed: (){
                                      setState(() {
                                        GlobalVariables.no_of_cart_items+=1;
                                        GlobalVariables.allcartitems[widget.menuitem[0]][0]+=1;
                                        GlobalVariables.totalcost+=GlobalVariables.allcartitems[widget.menuitem[0]][1];
                                        // SET BADGE HERE
                                      });
                                    },
                                    elevation: 1,
                                    child: Icon(Icons.add, size: 20),
                                    backgroundColor: Colors.green[300],
                                    mini:true,
                                    shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5.0))),
                                  ),
                                )
                              ],
                            )
                        )
                      ],
                    ),
                  ),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

This is cart.dart :

import 'dart:convert';
import 'package:canteen_app/pages/globalvar.dart';
import 'package:canteen_app/pages/globalvar.dart' as prefix0;
import 'package:canteen_app/pages/orderReceipt.dart';
import 'package:flutter/material.dart';
import 'package:canteen_app/pages/CustomShapeClipper.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';

class Cart extends StatefulWidget {
  @override
  _CartState createState() => _CartState();
}

class _CartState extends State<Cart> {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        CartTopPart(),
        CartBottomPart()
      ],
    );
  }
}

class CartTopPart extends StatefulWidget {
  @override
  _CartTopPartState createState() => _CartTopPartState();
}

Color firstColor = Color(0xFFF47D15);
Color secondColor = Color(0xFFEF772C);

class _CartTopPartState extends State<CartTopPart> {
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        ClipPath(
            clipper: CustomShapeClipper(),
            child: Container(
                height:140.0,
                width:MediaQuery.of(context).size.width,
                decoration: BoxDecoration(
                    gradient: LinearGradient(
                      colors: [firstColor, secondColor],
                    )
                ),
                child: Column(
                  children: <Widget>[
                    SizedBox(height: 53.0),
                    Text(
                      'CART',
                      style: TextStyle(
                        fontSize: 30.0,
                        color: Colors.white,
                      ),
                      textAlign: TextAlign.center,
                    ),
                  ],
                )
            )
        )
      ],
    );
  }
}

var cartmenuitems = GlobalVariables.allcartitems.keys.toList();


class CartBottomPart extends StatefulWidget {
  @override
  _CartBottomPartState createState() => _CartBottomPartState();
}

class _CartBottomPartState extends State<CartBottomPart> {

  bool _isLoading=false;

  createAlertDialog(BuildContext context, String errormessage){
    return showDialog(
        context: context,
        builder: (context){
          return AlertDialog(
              content: Text(errormessage)
          );
        }
    );
  }

  @override
  Widget build(BuildContext context) {
    if(GlobalVariables.no_of_cart_items>0) {
      return _isLoading==true ? Center(child: CircularProgressIndicator()) : Padding(
        padding: const EdgeInsets.fromLTRB(20, 10, 20, 10),
        child: Column(
          children: <Widget>[
            Container(
              height: MediaQuery
                  .of(context)
                  .size
                  .height * 0.40,
              child: ListView(
                padding: EdgeInsets.fromLTRB(0, 10, 0, 0),
                scrollDirection: Axis.vertical,
                children: cartmenuitems.map((menuitem) {
                  //print(cartmenuitems);
                 // print(GlobalVariables.allcartitems[menuitem]);
                  //if(GlobalVariables.allcartitems[menuitem]>=1) {
                    //print('heyy');
                    return CartOrderDish(menuitem: menuitem);
                  //}
                }).toList()
              ),
            ),
            Divider(
                color: Colors.black
            ),
            Row(
              children: <Widget>[
                Text(
                  'Total Amount:',
                  style: TextStyle(
                      fontSize: 20
                  ),
                ),
                SizedBox(width: 140),
                Row(
                  children: <Widget>[
                    Text(
                      '₹',
                      style: TextStyle(
                          fontSize: 20
                      ),
                    ),
                    Text(
                      GlobalVariables.totalcost.toString(),
                      style: TextStyle(
                        fontSize: 20
                      )
                    )
                  ],
                )
              ],
            ),
            SizedBox(height: 5),
            Align(
              alignment: Alignment.centerLeft,
              child: Text(
                '(Inclusive of GST)',
                style: TextStyle(
                    fontSize: 15
                ),
              ),
            ),
            SizedBox(height: 18),
            RaisedButton(
                onPressed: () {

                  if((GlobalVariables.accountbalance-GlobalVariables.totalcost)<0){
                    createAlertDialog(context, "Whoops! The total cost exceeds your account balance!\n\nYour account balance can be updated at the CASH COUNTER.");
                  }
                  else {
                    setState(() {
                      _isLoading = true;
                    });

                    // creating a list of all cart items to send to php
                    List cart = [];
                    cartmenuitems.map((menuitem) {
                      if (GlobalVariables.allcartitems[menuitem][0] > 0) {
                        cart.add([menuitem, GlobalVariables.allcartitems[menuitem][0], GlobalVariables.allcartitems[menuitem][1] * GlobalVariables.allcartitems[menuitem][0]]);
                      }
                    }).toList();
                    print(jsonEncode(cart));

                    Future placeOrderFunction() async {
                      print(GlobalVariables.username);
                      final response = await http.post(
                          "https://kjscecanteenapp.000webhostapp.com/place_order_sys.php",
                          body: {
                            "cart": json.encode(cart),
                            "username": GlobalVariables.username
                          });
                      // print(response.body);
                      var decodedResponse = json.decode(response.body);
                      print(decodedResponse);

                      setState(() {
                        _isLoading = false;
                      });

                      if (decodedResponse['error'] != -1) {
                        // means no error
                        int orderId=decodedResponse['error'];
                        int cost=GlobalVariables.totalcost;
                        GlobalVariables.no_of_cart_items = 0;
                        String date=DateFormat('dd-MMM-yyyy').format(DateTime.now());

                        cartmenuitems.map((menuitem) {
                          if (GlobalVariables.allcartitems[menuitem][0] > 0) {
                            GlobalVariables.allcartitems[menuitem][0] = 0;
                          }
                        });

                        GlobalVariables ob = new GlobalVariables();
                        ob.resetcart();
                        GlobalVariables.accountbalance -= GlobalVariables.totalcost;
                        GlobalVariables.totalcost = 0;

                        Navigator.of(context)
                            .push(MaterialPageRoute<Null>(
                            builder: (BuildContext context) {
                              return new OrderReceipt(orderId: orderId, cost: cost, date: date, cart: cart);
                            }));
                      }
                      else{
                        createAlertDialog(context, "There was some error during the order placement. Don't worry tho try again in a few seconds!");
                      }

                    }

                    placeOrderFunction();
                  }

                },
                elevation: 5.0,
                textColor: Colors.white,
                shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(5.0)),
                padding: const EdgeInsets.all(0.0),
                child: Container(
                  decoration: const BoxDecoration(
                      gradient: LinearGradient(
                          colors: <Color>[
                            Color(0xFF0083B0),
                            Color(0xFF00B4DB),
                          ]
                      )
                  ),
                  padding: const EdgeInsets.fromLTRB(40, 15, 40, 15),
                  child: Text(
                    'Place Order',
                    style: TextStyle(
                        fontSize: 20
                    ),
                  ),
                )
            )
          ],
        ),
      );
    }
    else {
      return Padding(
        padding: const EdgeInsets.all(20.0),
        child: Container(
          height: MediaQuery.of(context).size.height*0.6,
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Text(
                'Please add some items into your cart.',
                style: TextStyle(
                  fontSize: 20,
                ),
                textAlign: TextAlign.center,
              ),
            ],
          ),
        ),
      );
    }
  }
}

class CartOrderDish extends StatefulWidget {

  String menuitem;
  CartOrderDish({Key key, this.menuitem}): super(key: key);

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

class _CartOrderDishState extends State<CartOrderDish> {
  @override
  Widget build(BuildContext context) {
    if(GlobalVariables.allcartitems[widget.menuitem][0]>0) {
      int price=GlobalVariables.allcartitems[widget.menuitem][0]*GlobalVariables.allcartitems[widget.menuitem][1];
      return Padding(
        padding: const EdgeInsets.fromLTRB(0, 0, 0, 10),
        child: Row(
          children: <Widget>[
            Expanded(
              child: Text(
                widget.menuitem,
                style: TextStyle(
                    fontSize: 20
                ),
              ),
            ),
            SizedBox(width: 50),
            Container(
                child: Row(
                  children: <Widget>[
                    SizedBox(
                      width: 30,
                      height: 30,
                      child: FloatingActionButton(
                        heroTag: 'fab1',
                        elevation: 1,
                        child: Icon(Icons.remove, size: 18),
                        backgroundColor: Colors.red[300],
                        mini: true,
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.all(Radius.circular(5.0))),
                      ),
                    ),
                    Padding(
                      padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
                      child: Text(
                        GlobalVariables.allcartitems[widget.menuitem][0].toString(),
                        style: TextStyle(
                            fontSize: 18
                        ),
                      ),
                    ),
                    SizedBox(
                      width: 30,
                      height: 30,
                      child: FloatingActionButton(
                        heroTag: 'fab2',
                        elevation: 1,
                        child: Icon(Icons.add, size: 20),
                        backgroundColor: Colors.green[300],
                        mini: true,
                        shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.all(Radius.circular(5.0))),
                      ),
                    )
                  ],
                )
            ),
            SizedBox(width: 50),
            Row(
              children: <Widget>[
                Text(
                  '₹',
                  style: TextStyle(
                      fontSize: 20
                  ),
                ),
                Text(
                  price.toString(),
                  style: TextStyle(
                    fontSize:20
                  )
                )
              ],
            )
          ],
        ),
      );
    }
    else{
      return Container();
    }
  }
}

Instead of changing the entire icon to indicate items added to cart, you could use Badge
Badge package: https://pub.dev/packages/badges

Update-1: For implementing the badges:

var p1badge = false;
var p2badge = false;
List<BottomNavigationBarItem> buildBottomNavBarItems() {
    return [
      BottomNavigationBarItem(
          icon: Badge(
            showBadge: p1badge,
            child: Icon(Icons.filter_1),
          ),
          title: Text('Page-1')),
      BottomNavigationBarItem(
          icon: Badge(
            showBadge: p2badge,
            child: Icon(Icons.filter_2),
          ),
          title: Text('Page-2'))
    ];
  }

Use a VoidCallback to update the badge:

class Page1 extends StatelessWidget {
  VoidCallback onP1Badge;

  Page1({this.onP1Badge});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        RaisedButton(
          child: Text('P1 BADGE'),
          onPressed: () {onP1Badge();},
        ),
      ],
    );
  }
}

Change the value of p1badge to true and call setState() :

pages = [
      Page1(
        onP1Badge: () {
          p1badge = true;
          setState(() {});
        },
      ),
      Page2()
    ]; 

Update-2: Check this out: https://github.com/TheArhaam/Flutter-BottomNavigationBar-Badge
GIF:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM