Related
i want to implement the sliver app bar as shown in the the 2 pictures given below. After much googling , I fount about the CustomScrollView widget and the SliverAppBar widget but all the tutorials and blogs online about sliver app bars show a simple one where an image disappears into an app bar with a text as title on scrolling. However here what I want to achieve is slightly different and I am having a hard time trying to figure out how to do it. Can anyone help me with it?
You can try this:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ScrollController? _scrollController;
bool lastStatus = true;
double height = 200;
void _scrollListener() {
if (_isShrink != lastStatus) {
setState(() {
lastStatus = _isShrink;
});
}
}
bool get _isShrink {
return _scrollController != null &&
_scrollController!.hasClients &&
_scrollController!.offset > (height - kToolbarHeight);
}
#override
void initState() {
super.initState();
_scrollController = ScrollController()..addListener(_scrollListener);
}
#override
void dispose() {
_scrollController?.removeListener(_scrollListener);
_scrollController?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final TextTheme textTheme = Theme.of(context).textTheme;
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData.dark(),
title: 'Horizons Weather',
home: Scaffold(
body: NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (context, innerBoxIsScrolled) {
return [
SliverAppBar(
elevation: 0,
backgroundColor: Colors.blueGrey,
pinned: true,
expandedHeight: 275,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.parallax,
title: _isShrink
? const Text(
"Profile",
)
: null,
background: SafeArea(
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 48),
child: ClipRRect(
borderRadius: BorderRadius.circular(100),
child: Image.network(
headerImage,
fit: BoxFit.cover,
height: 100,
width: 100,
),
),
),
const SizedBox(
height: 16,
),
Text(
"Flipkart",
style: textTheme.headline4,
),
const SizedBox(
height: 8,
),
const Text(
"flipkart.com",
),
const SizedBox(
height: 5,
),
const Text(
"Info about the company",
),
],
),
),
),
actions: _isShrink
? [
Padding(
padding: const EdgeInsets.only(left: 8, right: 12),
child: Row(
children: [
Padding(
padding:
const EdgeInsets.only(left: 8, right: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
Text(
"Flipkart",
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
"flipkart.com",
style: TextStyle(
fontSize: 12,
),
),
],
),
),
ClipRRect(
borderRadius: BorderRadius.circular(100),
child: Image.network(
headerImage,
fit: BoxFit.cover,
height: 30,
width: 30,
),
),
],
),
),
]
: null,
),
];
},
body: CustomScrollView(
scrollBehavior: const ConstantScrollBehavior(),
slivers: [
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Center(child: Text("Item: $index")),
);
},
childCount: 50,
),
),
],
),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
const UserAccountsDrawerHeader(
accountName: Text("Zakaria Hossain"),
accountEmail: Text("zakariaaltime#gmail.com"),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.orange,
child: Text(
"A",
style: TextStyle(fontSize: 40.0),
),
),
),
ListTile(
leading: Icon(Icons.home),
title: Text("Home"),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text("Settings"),
onTap: () {
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.contacts),
title: Text("Contact Us"),
onTap: () {
Navigator.pop(context);
},
),
],
),
),
),
);
}
}
Demo
I am calling API data inside Listview. builder in flutter but the error I am facing is the items are changing their positions automatically.
For Example, When I load this class for the First Time the arrangement of List items is the same as required but after 30-40 seconds the List items arrangement automatically starts changing, and data showing itself randomly.
I am looking for someone who can help me to fix this issue?
For this purpose here is myClass Code.
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart'as HTTP;
import 'package:worldcup/utils/colors.dart';
class SeriesSchedulePage extends StatefulWidget {
#override
_SeriesSchedulePageState createState() => _SeriesSchedulePageState();
}
class _SeriesSchedulePageState extends State<SeriesSchedulePage> {
List<dynamic> matches = [];
var match;
getSchedule() async {
http.Response response = await http
.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
final Map parseData = await json.decode(response.body.toString());
matches = parseData['matchList']["matches"];
setState(() {
match = matches;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColors.primaryWhite,
appBar: AppBar(
backgroundColor: AppColors.yellow,
elevation: 0,
centerTitle: true,
leading: IconButton(
onPressed: () {
Navigator.pop(context,true);
},
icon: Icon(
Icons.arrow_back,
color: Colors.white,
),
),
title: Text(
'Schedule',
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
color: Colors.white,
fontWeight: FontWeight.w600,
fontSize: 17),
),
),
body: Container(
child: FutureBuilder(
future: getSchedule(),
builder: (context, snapshot) {
if (match == null) {
return Center(
child: CupertinoActivityIndicator(
animating: true, radius: 15));
} else
return ListView.builder(
itemCount: matches.length,
shrinkWrap: true,
reverse: false,
itemBuilder: (context, index) {
if (matches[index]["status"] =="UPCOMING") {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
child: Container(
width: double.infinity,
child: Padding(
padding: EdgeInsets.only(left: 15, top: 7, bottom: 7, right: 15),
child: Row(
children: [
SizedBox(width: 20,),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
matches[index]['name'].toString(),
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
fontWeight: FontWeight.w700, fontSize: 15),
),
SizedBox(height: 10,),
Text(
matches[index]["homeTeam"]['name'].toString(),
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
fontWeight: FontWeight.w700, fontSize: 15),
),
SizedBox(height: 10,),
Text(
matches[index]["awayTeam"]['name'].toString(),
textScaleFactor: 0.9,
style: GoogleFonts.openSans(
fontWeight: FontWeight.w500, fontSize: 13),
),
],
),
],
),
),
],
),
),
)
);
} else {
return Center(
child: Text("No Upcoming Match in this series"),
);
}
}
);
},
),
)
);
}
}
The issue is because getSchedule() has a setState inside it. When the build method is called, getSchedule() will trigger, and since it is calling setState , the build method is being called again, causing your widgets to continuously rebuild in an infinite loop.
What you need to do is prevent such a loop from happening. I see that you are using FutureBuilder too, that is a solution but your implementation is incorrect.
What you should do is this:
Future<List<dynamic>> getSchedule() async {
http.Response response =
await http.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
final Map parseData = await json.decode(response.body.toString());
var matches = parseData['matchList']["matches"];
return matches;
}
This function returns a Future<List<dynamic>> which your future builder can use to handle the builds. For info on future builder here https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html.
Since you FutureBuilder will react to what is provided by getSchedule() when the future is complete, you do not need to use setState to rebuild.
I have modified your SeriesShedualPage here is the full code:
class SeriesSchedulePage extends StatefulWidget {
#override
_SeriesSchedulePageState createState() => _SeriesSchedulePageState();
}
class _SeriesSchedulePageState extends State<SeriesSchedulePage> {
Future<List<dynamic>> getSchedule() async {
http.Response response =
await http.get(Uri.parse("https://api.cricket.com.au/matches/2780"));
final Map parseData = await json.decode(response.body.toString());
var matches = parseData['matchList']["matches"];
return matches;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: FutureBuilder<List<dynamic>>(
future: getSchedule(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<dynamic> matches = snapshot.data!;
return ListView.builder(
itemCount: matches.length,
shrinkWrap: true,
reverse: false,
itemBuilder: (context, index) {
if (matches[index]["status"] == "UPCOMING") {
return Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(7),
),
child: Container(
width: double.infinity,
child: Padding(
padding: EdgeInsets.only(
left: 15, top: 7, bottom: 7, right: 15),
child: Row(
children: [
SizedBox(
width: 20,
),
Expanded(
flex: 2,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
matches[index]['name'].toString(),
textScaleFactor: 0.9,
),
SizedBox(
height: 10,
),
Text(
matches[index]["homeTeam"]['name']
.toString(),
textScaleFactor: 0.9,
),
SizedBox(
height: 10,
),
Text(
matches[index]["awayTeam"]['name']
.toString(),
textScaleFactor: 0.9,
),
],
),
],
),
),
],
),
),
));
} else {
return Center(
child: Text("No Upcoming Match in this series"),
);
}
});
}
return Center(
child: CupertinoActivityIndicator(animating: true, radius: 15));
},
),
));
}
}
I am having a stuck on transferring the value from the second page to the third page using the value pass from the first page. when I am trying to use the usual way that I am used to calling the data in the stateful widget, it returns an error on undefined.
class restaurantLISTVIEW extends StatefulWidget {
restaurantLISTVIEW({this.category});
final String category;
#override
_restaurantLISTVIEWState createState() => _restaurantLISTVIEWState();
}
within extends state:(working)
FloatingActionButton(
onPressed: (){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(
'${widget.category}'
),
);
},
);
},),
error on extends stateless widget, return null: (not working)
onTap: ()
{
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new SarapanPagi(list: list, index: i, category: category)));
}
within extends stateless:(not working)
FloatingActionButton(
onPressed: (){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(
'$category hellp'
),
);
},
);
},),
The whole code on the second page:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:http/http.dart' as HTTP;
import 'breakfast.dart';
// ignore: camel_case_types
class restaurantLISTVIEW extends StatefulWidget {
restaurantLISTVIEW({this.category});
final String category;
#override
_restaurantLISTVIEWState createState() => _restaurantLISTVIEWState();
}
// ignore: camel_case_types
class _restaurantLISTVIEWState extends State<restaurantLISTVIEW> {
Future<List> getData() async{
var url = 'http://10.0.2.2/foodsystem/restaurantlist.php';
var data = {'product_type': 'xde pape ppon saje nk hantar value'};
var response = await http.post(url, body: json.encode(data));
//final response= await http.get("http://10.0.2.2/foodsystem/getdata.php");
return json.decode(response.body);}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
//Text("Restaurant's Owner Page"),
Text('${widget.category}', textAlign: TextAlign.center, style: TextStyle(fontSize: 25, fontWeight: FontWeight.w700), ),
],
),
centerTitle: false,
//automaticallyImplyLeading: false,
),
body:
Padding(
padding: const EdgeInsets.only(bottom: 20, left: 5, right: 5),
child: Column(
children: [
SizedBox(height: 30,),
Container(
//decoration: BoxDecoration(border: Border.all(color: Colors.black, width: 4), borderRadius: BorderRadius.circular(15)),
height: 600,
child: FutureBuilder<List>(
future: getData(),
builder: (context, snapshot){
if(snapshot.hasError) print(snapshot.error);
return snapshot.hasData ?
ItemList(list: snapshot.data,) :
Center(child: CircularProgressIndicator(),);
},
),
),
FloatingActionButton(
onPressed: (){
return showDialog(
context: context,
builder: (context){
return AlertDialog(
content: Text(
'${widget.category}'
),
);
},
);
},
),
SizedBox(height: 10,),
],
),
),
);
}
}
class ItemList extends StatelessWidget {
final List list;
final String category;
ItemList({this.list, this.category});
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
//color: Colors.red.shade100,
height: 600,
child: ListView.builder(
itemCount: list==null ? 0 : list.length,
itemBuilder: (context, i){
return new Container(
height: 200,
child: new GestureDetector(
onTap: ()
{
if(widget.category == "Breakfast"){
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new SarapanPagi(list: list, index: i, category: category)));
}
},
child: new Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
constraints: BoxConstraints(minWidth: 180, maxWidth: 180),
child:
Column(
children: [
Text(list[i]["restaurant_name"], style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), textAlign: TextAlign.center,),
Text("Restaurant ID: ${list[i]["restaurant_id"]}", style: TextStyle(fontSize: 20,), textAlign: TextAlign.center,),
],
),
),
Padding(
padding: const EdgeInsets.only(left :20.0),
child: Container(
constraints: BoxConstraints(minWidth: 150, maxWidth: 300),
child:
SizedBox(
width: 50,
child: Column(
children: [
Text("SSM: ${list[i]["restaurant_ssm"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 15),),
Text("Phone: ${list[i]["restaurant_phone"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 15),),
Text("Address: ${list[i]["restaurant_address"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 15),),
],
),
),
),
),
],
),
Row(
children: [
],
),
],
),
),
),
);
},
),
),
);
The whole code on the third page:
import 'dart:convert';
import 'package:http/http.dart' as HTTP;
import 'package:flutter/material.dart';
//import 'globals.dart' as globals;
class SarapanPagi extends StatefulWidget {
final List list;
final int index;
final String category;
SarapanPagi({this.index,this.list,this.category});
#override
_SarapanPagiState createState() => _SarapanPagiState();
}
class _SarapanPagiState extends State<SarapanPagi> {
Future<List> getData() async{
var url = 'http://10.0.2.2/foodsystem/breakfastlist.php';
var data = {
'product_type': 'Breakfast',
'product_owner': widget.list[widget.index]['restaurant_id'],
};
var response = await http.post(url, body: json.encode(data));
//final response= await http.get("http://10.0.2.2/foodsystem/getdata.php");
return json.decode(response.body);}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
title: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
//Text("Restaurant's Owner Page"),
Text(widget.list[widget.index]['restaurant_name'], textAlign: TextAlign.center, style: TextStyle(fontWeight: FontWeight.w700), ),
],
),
centerTitle: false,
//automaticallyImplyLeading: false,
),
body:
Padding(
padding: const EdgeInsets.only(bottom: 20, left: 5, right: 5),
child: Column(
children: [
SizedBox(height: 30,),
Container(
//decoration: BoxDecoration(border: Border.all(color: Colors.black, width: 4), borderRadius: BorderRadius.circular(15)),
height: 600,
child: FutureBuilder<List>(
future: getData(),
builder: (context, snapshot){
if(snapshot.hasError) print(snapshot.error);
return snapshot.hasData ?
ItemList(list: snapshot.data,) :
Center(child: CircularProgressIndicator(),);
},
),
),
SizedBox(height: 10,),
],
),
),
);
}
}
class ItemList extends StatelessWidget {
final List list;
ItemList({this.list});
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Container(
//color: Colors.red.shade100,
height: 600,
child: ListView.builder(
itemCount: list==null ? 0 : list.length,
itemBuilder: (context, i){
return new Container(
height: 200,
child: new GestureDetector(
onTap: (){},
child: new Card(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
"images/${list[i]['image']}",
width: 150,
height: 150,
),
),
Padding(
padding: const EdgeInsets.only(left: 20.0, bottom: 0),
child:
Column(
children: [
Text(list[i]["product_name"], textAlign: TextAlign.center, style: TextStyle(fontSize: 30),),
Text("Price RM : ${list[i]["product_price"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 25),),
RaisedButton(
shape: RoundedRectangleBorder(borderRadius: new BorderRadius.circular(40.0)),
color: Colors.red.shade300,
child: Text("Add to Cart", style: TextStyle(fontWeight: FontWeight.bold),),
onPressed: (){},
)
],
),
),
],
),
/*ListTile(
title: Text(list[i]["product_name"], textAlign: TextAlign.center, style: TextStyle(fontSize: 30),),
leading:
Image.asset(
"images/${list[i]['image']}",
width: 100,
height: 100,
),
subtitle: Text("Price RM : ${list[i]["product_price"]}", textAlign: TextAlign.center, style: TextStyle(fontSize: 25),),
),*/
],
),
),
),
);
},
),
),
);
The
You are not using widget.category in restaurantLISTVIEW page but in ItemList widget, that's why you are getting that error.
Adjust your ItemList widget like this
class ItemList extends StatelessWidget {
final List list;
final String category;
ItemList({this.list, this.category});
}
So, your navigation line in ItemList must be
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context)=> new SarapanPagi(list: list, index: i, category: category)));
Also, in SarapanPagi page the variable type of category is not int by String
You are not using widget.category in restaurantLISTVIEW page but in ItemList widget,
The solution that I made is:
this code on the stateful widget class for the second page, needs to be improved by adding the value of the category.
ItemList(list: snapshot.data,)
improved code:
this code forwards the value store in the widget category to the second page from the stateful widget into stateless widget.
ItemList(list: snapshot.data,category: widget.category) :
I create Welcome Page, when clicking the button I would like the user to be redirected to the home page, but when I click it gives several errors. I don't know how to program very well in flutter, can someone help me?
I tried in many ways, and they all fail. If you have to press the button to restart the APP it would also work, but I don't know how to solve it in any way
WELCOME PAGE (I would like to be redirected to HOME by clicking the button)
import 'package:flutter/material.dart';
import '../../main.dart';
import '../models/items.dart';
import '../helpers/helper.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter/cupertino.dart';
void main() => runApp(Welcome());
Future<void> Return() async {
runApp(MyApp());
}
class Welcome extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: WelcomeScreen(),
);
}
}
class WelcomeScreen extends StatefulWidget {
final GlobalKey<ScaffoldState> parentScaffoldKey;
WelcomeScreen({Key key, this.parentScaffoldKey}) : super(key: key);
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen> {
List<Widget> slides = items
.map((item) => Container(
padding: EdgeInsets.symmetric(horizontal: 18.0),
child: Column(
children: <Widget>[
Flexible(
flex: 1,
fit: FlexFit.tight,
child: Image.asset(
item['image'],
fit: BoxFit.fitWidth,
width: 220.0,
alignment: Alignment.bottomCenter,
),
),
Flexible(
flex: 1,
fit: FlexFit.tight,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 30.0),
child: Column(
children: <Widget>[
Text(item['header'],
style: TextStyle(
fontSize: 50.0,
fontWeight: FontWeight.w300,
color: Color(0XFF3F3D56),
height: 2.0)),
Text(
item['description'],
style: TextStyle(
color: Colors.grey,
letterSpacing: 1.2,
fontSize: 16.0,
height: 1.3),
textAlign: TextAlign.center,
)
],
),
),
)
],
)))
.toList();
double currentPage = 0.0;
final _pageViewController = new PageController();
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: Helper.of(context).onWillPop,
child: Scaffold(
body: Stack(
alignment: AlignmentDirectional.topCenter,
children: <Widget>[
PageView.builder(
controller: _pageViewController,
itemCount: slides.length,
itemBuilder: (BuildContext context, int index) {
_pageViewController.addListener(() {
setState(() {
currentPage = _pageViewController.page;
});
});
return slides[index];
},
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
margin: EdgeInsets.only(top: 70.0),
padding: EdgeInsets.symmetric(vertical: 40.0),
)
),
Positioned(
bottom: 10,
child: RaisedButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context){
return HomeWidget();
},
highlightElevation: 2,
splashColor: Color(0xFF2F4565),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)
),
padding: EdgeInsets.symmetric(horizontal: 40),
color: Color(0XFFEA5C44),
child: Text(
"Permitir",
style: TextStyle(color: Colors.white),
),
),
)
],
),
),
);
}
}
HOMEPAGE (I would like to be redirected to that page by clicking the button on the WELCOME page)
import 'package:flutter/material.dart';
import 'package:mvc_pattern/mvc_pattern.dart';
import '../../generated/l10n.dart';
import '../controllers/home_controller.dart';
import '../elements/CardsCarouselWidget.dart';
import '../elements/CaregoriesCarouselWidget.dart';
import '../elements/DeliveryAddressBottomSheetWidget.dart';
import '../elements/GridWidget.dart';
import '../elements/ProductsCarouselWidget.dart';
import '../elements/ReviewsListWidget.dart';
import '../elements/SearchBarWidget.dart';
import '../elements/ShoppingCartButtonWidget.dart';
import '../repository/settings_repository.dart' as settingsRepo;
import '../repository/user_repository.dart';
class HomeWidget extends StatefulWidget {
final GlobalKey<ScaffoldState> parentScaffoldKey;
HomeWidget({Key key, this.parentScaffoldKey}) : super(key: key);
#override
_HomeWidgetState createState() => _HomeWidgetState();
}
class _HomeWidgetState extends StateMVC<HomeWidget> {
HomeController _con;
#override
_HomeWidgetState() : super(HomeController()) {
_con = controller;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: new IconButton(
icon: new Icon(Icons.sort, color: Theme.of(context).hintColor),
onPressed: () => widget.parentScaffoldKey.currentState.openDrawer(),
),
automaticallyImplyLeading: false,
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
title: ValueListenableBuilder(
valueListenable: settingsRepo.setting,
builder: (context, value, child) {
return Text(
value.appName ?? S.of(context).home,
style: Theme.of(context).textTheme.headline6.merge(TextStyle(letterSpacing: 1.3)),
);
},
),
actions: <Widget>[
new ShoppingCartButtonWidget(iconColor: Theme.of(context).hintColor, labelColor: Theme.of(context).accentColor),
],
),
body: RefreshIndicator(
onRefresh: _con.refreshHome,
child: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 0, vertical: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: SearchBarWidget(
onClickFilter: (event) {
widget.parentScaffoldKey.currentState.openEndDrawer();
},
),
),
Padding(
padding: const EdgeInsets.only(top: 15, left: 20, right: 20),
child: ListTile(
dense: true,
contentPadding: EdgeInsets.symmetric(vertical: 0),
leading: Icon(
Icons.stars,
color: Theme.of(context).hintColor,
),
trailing: IconButton(
onPressed: () {
if (currentUser.value.apiToken == null) {
_con.requestForCurrentLocation(context);
} else {
var bottomSheetController = widget.parentScaffoldKey.currentState.showBottomSheet(
(context) => DeliveryAddressBottomSheetWidget(scaffoldKey: widget.parentScaffoldKey),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)),
),
);
bottomSheetController.closed.then((value) {
_con.refreshHome();
});
}
},
icon: Icon(
Icons.my_location,
color: Theme.of(context).hintColor,
),
),
title: Text(
S.of(context).top_markets,
style: Theme.of(context).textTheme.headline4,
),
subtitle: Text(
S.of(context).near_to + " " + (settingsRepo.deliveryAddress.value?.address ?? S.of(context).unknown),
style: Theme.of(context).textTheme.caption,
),
),
),
CardsCarouselWidget(marketsList: _con.topMarkets, heroTag: 'home_top_markets'),
ListTile(
dense: true,
contentPadding: EdgeInsets.symmetric(horizontal: 20),
leading: Icon(
Icons.trending_up,
color: Theme.of(context).hintColor,
),
title: Text(
S.of(context).trending_this_week,
style: Theme.of(context).textTheme.headline4,
),
subtitle: Text(
S.of(context).clickOnTheProductToGetMoreDetailsAboutIt,
maxLines: 2,
style: Theme.of(context).textTheme.caption,
),
),
ProductsCarouselWidget(productsList: _con.trendingProducts, heroTag: 'home_product_carousel'),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListTile(
dense: true,
contentPadding: EdgeInsets.symmetric(vertical: 0),
leading: Icon(
Icons.category,
color: Theme.of(context).hintColor,
),
title: Text(
S.of(context).product_categories,
style: Theme.of(context).textTheme.headline4,
),
),
),
CategoriesCarouselWidget(
categories: _con.categories,
),
Padding(
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20),
child: ListTile(
dense: true,
contentPadding: EdgeInsets.symmetric(vertical: 0),
leading: Icon(
Icons.trending_up,
color: Theme.of(context).hintColor,
),
title: Text(
S.of(context).most_popular,
style: Theme.of(context).textTheme.headline4,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: GridWidget(
marketsList: _con.popularMarkets,
heroTag: 'home_markets',
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ListTile(
dense: true,
contentPadding: EdgeInsets.symmetric(vertical: 20),
leading: Icon(
Icons.recent_actors,
color: Theme.of(context).hintColor,
),
title: Text(
S.of(context).recent_reviews,
style: Theme.of(context).textTheme.headline4,
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ReviewsListWidget(reviewsList: _con.recentReviews),
),
],
),
),
),
);
}
}
First you need to set up the route:
MaterialApp(
// Start the app with the "/" named route. In this case, the app starts
// on the FirstScreen widget.
initialRoute: '/',
routes: {
// When navigating to the "/" route, build the FirstScreen widget.
'/': (context) => FirstScreen(), //NOTE: Change the FirstScreen() to your own screen's class name (ex: WelcomeScreen())
// When navigating to the "/second" route, build the SecondScreen widget.
'/second': (context) => SecondScreen(), //NOTE: Change the SecondScreen() to your own screen's class name (ex: HomeWidget())
'/third': (context) => ThirdScreen(),
},
);
And then, inside your button, navigate to the page:
// Within the `FirstScreen` widget
onPressed: () {
// Navigate to the second screen using a named route.
Navigator.pushNamed(context, '/second');
}
NOTE: One of your pages must be named as / to prevent error, for the full tutorial please visit this link
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: