I am working on an flutter application where it has more than 5 screens, I want to handle the back button of android, for example, when I logged in on app, it display the dashboard screen, so when I move to profile and then move to history screen, and when I click on back button on history screen it should navigate to profile screen, because the last screen I visited before history screen is profile, but it display the first screen which login screen.
I found the solution which works like when I click on back button it close the app.
Update:
My screens are navigating from drawer and from bottom navigation, there is only login screen where i use login button and calling dashboard screen onpressed function, other than this there is no button on any screen which navigate to other screens. here is the code for drawer and bottom navigation.
this is line of code i am using on login button
Navigator.push(
context, new MaterialPageRoute(builder: (context) => Employee()));
drawer and bottom navigation code:
Code:
class Employee extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primaryColor: Colors.blue
),
home: EmployeeNavigation(),
);
}
}
int _selectedTab = 0;
final _pageOptions = [
EmployeeDashboard(),
location(),
Profile()
];
String getname="";
String getemail="";
String getdesignation="";
String getaccesstoken="";
String getdate;
String getTime;
// ignore: must_be_immutable
class EmployeeNavigation extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return EmployeeNavigationState();
}
}
class EmployeeNavigationState extends State<EmployeeNavigation> {
var email;
var designation;
var date;
bool valuefirst = false;
String backtext="";
#override
Widget build(BuildContext context) {
//i used this too but it doesn't work.
return WillPopScope(
onWillPop: () async {
if (_selectedTab == 0) {
return true;
}
setState(() {
_selectedTab = 0;
});
return false;
},
child:Scaffold(
drawer:Emp_DrawerCode(),
body: _pageOptions[_selectedTab],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.blue[50],
type: BottomNavigationBarType.fixed,
currentIndex: _selectedTab,
onTap: (value) {
print(value);
setState(() {
_selectedTab = value;
});
},
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "Home"),
BottomNavigationBarItem(icon: Icon(Icons.location_on), label: "Location"),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: "Profile",
),
],
)));
}
}
class Emp_DrawerCode extends StatefulWidget {
#override
_Emp_DrawerCodeState createState() => _Emp_DrawerCodeState();
}
class _Emp_DrawerCodeState extends State<Emp_DrawerCode> {
SharedPreferences myPrefs;
name() async{
myPrefs=await SharedPreferences.getInstance();
setState(() {
getname=myPrefs.getString('name');
getemail=myPrefs.getString('email');
getdesignation=myPrefs.getString('designation');
});
}
void initState(){
name();
}
#override
Widget build(BuildContext context) {
return new Drawer(
child: new ListView(
padding: const EdgeInsets.all(0.0),
children: <Widget>[
new UserAccountsDrawerHeader(
accountName: new Text(getname),
accountEmail: new Text(getemail),
currentAccountPicture: new CircleAvatar(
backgroundColor:
Theme.of(context).platform == TargetPlatform.android
? Colors.white
: Colors.blue,
child: Text(
getname[0][0],
style: TextStyle(fontSize: 40.0),
),
),
),
new ListTile(
title: new Text('Home'),
leading: Icon(Icons.dashboard,color:Colors.grey),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=> EmployeeNavigation()
)
);
},
),
new ListTile(
title: new Text('Request for leave'),
leading: Icon(Icons.request_page,color:Colors.grey),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>RequestForLeave()
)
);
},
),
new ExpansionTile(
title: new Text('History'),
children: <Widget>[
ListTile(
title:new Text("My Attendance"),
leading: Icon(Icons.assessment_outlined ,color:Colors.grey),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>new MyAttendance()
)
);
},
),
ListTile(
title:new Text("Leaves"),
leading: Icon(Icons.assessment_outlined,color:Colors.grey ),
onTap: (){
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>new LeaveHistory()
)
);
},
),
],
leading: Icon(Icons.history,),
),
new ListTile(
title: new Text('Log out'),
leading: Icon(Icons.logout,color:Colors.grey),
onTap: (){
myPrefs.setBool('login', true);
Navigator.pop(context);
Navigator.push(context, new MaterialPageRoute(
builder: (context)=>
Login()
)
);
},
),
],
),
);
}
}
kindly please help how to do this.
I am using navigator.push method and it is acting as you want.
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back, color: Colors.blue),
onPressed: () => Navigator.of(context).pop(),
),
title: Text("Sample"),
centerTitle: true,
),
I wish it solve your problem.
You need to first clarify your question a bit more.
Are using page view/ are you talking about a scenario where all are separately navigable screens or some different scenario ?
I am considering it as the second scenario when all are separately navigable screens.
In that case, every time user navigates to next screen you must use Navigator.pushNamed() / Navigator.push() as for now I think you are using Navigator.pushReplacement() which is causing this issue probably.
Navigator is nothing but a class aware of the stack of screens in the memory and so are the functions it provides us with. A simple push would mean pushing over the last pushed screen whereas pushing a replacement would replace the last pushed screen ultimately preventing you from navigating to the last pushed screen. Exactly like how it would work for a stack data structure.
Firstly Wrap your Scaffold with WillPopScope
return WillPopScope(
onWillPop: _onBackPressed,
child : Scaffold());
And then you can call the Function that handles the back press.
// Back Button Android Behaviour
Future<bool> _onBackPressed() async {
final shouldPop = await showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Are you sure you want to leave this page?",
style: TextStyle(
color: Colors.black,
fontSize: 25.0,
fontWeight: FontWeight.w500,
),
),
actions: <Widget>[
SizedBox(width: 16),
InkWell(
onTap: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => HomeScreen(), // Destination
),
(route) => false,
);
},
child: Container(
padding: EdgeInsets.all(8.0),
child: Text(
"LEAVE",
style: TextStyle(
color: Colors.red,
fontSize: 20.0,
fontWeight: FontWeight.w500,
),
),
),
),
SizedBox(width: 8.0),
InkWell(
onTap: () => Navigator.of(context).pop(false),
child: Container(
padding: EdgeInsets.all(8.0),
child: Text(
"DO NOT LEAVE",
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
fontWeight: FontWeight.w500,
),
),
),
),
],
));
return shouldPop ?? false;
}
Related
I am trying to update page content when an action is called.
Below is a sample of the code under change notifier that receives the onTap: method, When I click it should update the stateless widget depending on the tab clicked.
MultiProvider(
providers: [
ChangeNotifierProvider.value(value: ScreenChange()),
ChangeNotifierProvider(create: (context) => UserRepository.instance())
],
child: Consumer<ScreenChange>(
builder: (context, ScreenChange screenChange, child) {
return Material(
child: SafeArea(
child:
InkWell(
onTap: () {
screenChange.changeHomeState(PageState.homescreen);
print("${screenChange.state}");
},
child: ListTile(
leading: Container(
decoration: BoxDecoration(boxShadow: <BoxShadow>[
BoxShadow(
color:
screenChange.state == PageState.homescreen
? Global.orange
: Colors.transparent,
blurRadius: blurRadius,
spreadRadius: spreadRadius,
offset: const Offset(5, 5),
)
]),
child: const Icon(
FontAwesomeIcons.home,
color: Global.yellow,
),
),
title: Text(
"Home",
style: GoogleFonts.acme(),
),
),
),
Below is the widget that I want to change/ update:
ChangeNotifierProvider(
create: (context) => ScreenChange(),
child: Consumer<ScreenChange>(
builder: (context, ScreenChange change, child) {
switch (change.state) {
case PageState.homescreen:
print('${change.state}');
return Home();
case PageState.categories:
print('${change.state}');
return const CategoryScreen();
case PageState.notification:
print('${change.state}');
return NotificationScreen();
default:
}
return Center(
child: Text("Something went wrong",
style: GoogleFonts.abel(
fontSize: 20,
)));
}),
),
Below is my change notifier class:
enum PageState {
homescreen,
categories,
account,
notification,
about,
shareApp
}
class ScreenChange extends ChangeNotifier {
PageState homeState = PageState.homescreen;
PageState get state => homeState;
void changeHomeState(PageState state) {
homeState = state;
notifyListeners();
}
}
I found the solution here , I was using
another change notifier provider which did not trigger ,
Therfore my solution: I MOVED MY MULTIPROVIDER ABOVE THE WIDGET I WAS TRING TO UPDATE
https://github.com/rrousselGit/provider/issues/231
I have a bottom navigation bar, that lets me navigate between pages, while keeping the Bottom Navigation bar in place (Using Persistent Bottom Navigation bar package)
I also want to have a extra navigation button, that sends me to another page not listed on the Bottom Navigation bar, but all the different ways I have tried, it pushes me to another page, that is not inside the wrapper.
How could I navigate to another page from AppBar (Page is not listed on the bottom navigation bar) without losing the Navigation bar?
Attatching wrapper code
class Wrapper extends StatefulWidget {
final BuildContext menuScreenContext;
Wrapper({Key key, this.menuScreenContext}) : super(key: key);
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
final AuthService _auth = AuthService();
PersistentTabController _controller;
bool _hideNavBar;
#override
void initState() {
super.initState();
_controller = PersistentTabController(initialIndex: 0);
_hideNavBar = false;
}
List<Widget> _buildScreens() {
return [
HomePage(
hideStatus:_hideNavBar,
),
Page1(),
Page2(),
Page3(),
Page4(
hideStatus:_hideNavBar,
),
];
}
List<PersistentBottomNavBarItem> _navBarsItems() {
return [
PersistentBottomNavBarItem(
icon: Icon(Icons.home),
title: "Home",
activeColor: Colors.blue,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.search),
title: ("Search"),
activeColor: Colors.teal,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.add),
title: ("Add"),
activeColor: Colors.deepOrange,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
PersistentBottomNavBarItem(
icon: Icon(Icons.settings),
title: ("Settings"),
activeColor: Colors.indigo,
inactiveColor: Colors.grey,
),
];
}
#override
Widget build(BuildContext context)
{
final user = Provider.of<NUser>(context);
if(user==null){
return Authenticate();}
else {
return Scaffold
(
drawer: Drawer(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>
[
TextButton
(child:Text('hey'), onPressed: ()
{
pushNewScreenWithRouteSettings(
context,
settings: RouteSettings(name:'/home'),
screen: HomePage());
}
),
ElevatedButton.icon(
onPressed: () async {await _auth.signOut();},
icon: Icon(Icons.person),
label: Text('Logout'),
),
],
),
),
),
appBar: AppBar(
actions: [
IconButton(iconSize: 150,icon: Image.asset("assets/BUTTON.png", color: Colors.black,height: 1000,width: 1000,), onPressed: ()
{
Navigator.push(context, MaterialPageRoute(builder: (context) => Profile()));
}),
ButtonTheme(
minWidth: 100.0,
height: 100.0,
child: TextButton(
onPressed: () {},
child: Text(" 4444 "),
),
),
],
),
body: PersistentTabView.custom
(
context,
controller: _controller,
screens: _buildScreens(),
confineInSafeArea: true,
itemCount: 5,
handleAndroidBackButtonPress: true,
resizeToAvoidBottomInset: false,
stateManagement: true,
hideNavigationBar: _hideNavBar,
screenTransitionAnimation: ScreenTransitionAnimation(
animateTabTransition: true,
curve: Curves.ease,
duration: Duration(milliseconds: 200),
),
customWidget: CustomNavBarWidget
(
items: _navBarsItems(),
onItemSelected: (index) {
setState(() {
_controller.index = index; // THIS IS CRITICAL!! Don't miss it!
});
},
selectedIndex: _controller.index,
),
),
);
}
}
}
class Profile extends StatefulWidget {
Profile({Key key}): super(key: key);
#override
_ProfileState createState() => _ProfileState();
}
class _ProfileState extends State<Profile> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title:Text('sample'),
),
);
}
}
I tried creating a class for the page in wrapper, but no luck. Other pages are individual files. I am trying to navigate with the AppBar Button
I'm getting started with flutter/dart and I'm trying to implement a simple note app using InheritedWidget and TextControllers, but when I add or edit some note it doesn't update the main screen. I printed the new notes list in console and it is updated with the addings and editings but is not updated in main screen, still showing the initial note list ({'title': 'someTitle1', 'text': 'someText1'}, ...).
main.dart :
void main() => runApp(NoteInheritedWidget(
MaterialApp(
title: 'Notes App',
home: HomeList(),
),
));
home screen scaffold body :
List<Map<String, String>> get _notes => NoteInheritedWidget.of(context).notes;
...
body: ListView.builder(
itemCount: _notes.length,
itemBuilder: (context, index) {
return Card(
margin: EdgeInsets.symmetric(vertical: 5, horizontal: 7),
child: ListTile(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => NotePage(noteMode: NoteMode.Editing, index: index))
);
print(_notes);
},
trailing: Icon(Icons.more_vert),
title: _NoteTitle(_notes[index]['title']),
subtitle: _NoteText(_notes[index]['text']),
),
);
},
),
Add/Edit Note page :
enum NoteMode {
Adding,
Editing
}
class NotePage extends StatefulWidget {
final NoteMode noteMode;
final int index;
const NotePage ({this.noteMode, this.index});
#override
_NotePageState createState() => _NotePageState();
}
class _NotePageState extends State<NotePage> {
final TextEditingController _titleController = TextEditingController();
final TextEditingController _textController = TextEditingController();
List<Map<String, String>> get _notes => NoteInheritedWidget.of(context).notes;
#override
void didChangeDependencies() {
if (widget.noteMode == NoteMode.Editing) {
_titleController.text = _notes[widget.index]['text'];
_textController.text = _notes[widget.index]['title'];
}
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.noteMode == NoteMode.Adding ? 'Add Note' : 'Edit Note'
),
centerTitle: true,
backgroundColor: Colors.indigo[700],
),
body: Padding(
padding: const EdgeInsets.symmetric(vertical: 30, horizontal: 20),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextField(
controller: _titleController,
decoration: InputDecoration(
hintText: 'Note Title',
border: OutlineInputBorder(),
),
),
SizedBox(height: 20),
TextField(
controller: _textController,
maxLines: 20,
decoration: InputDecoration(
hintText: 'Note Text',
border: OutlineInputBorder(),
),
),
SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
_NoteButton(Icons.save, 'Save', () {
final title = _titleController.text;
final text = _textController.text;
if (widget.noteMode == NoteMode.Adding) {
_notes.add({'title': title, 'text': text});
print(_notes);
} else if (widget.noteMode == NoteMode.Editing) {
_notes[widget.index] = {'title': title, 'text': text};
print(_notes);
}
Navigator.pop(context);
}),
_NoteButton(Icons.clear, 'Discard', () {
Navigator.pop(context);
}),
if (widget.noteMode == NoteMode.Editing)
_NoteButton(Icons.delete, 'Delete', () {
_notes.removeAt(widget.index);
Navigator.pop(context);
}),
],
),
],
),
),
),
);
}
}
InheritedWidget :
class NoteInheritedWidget extends InheritedWidget {
final notes = [
{'title': 'someTitle1', 'text': 'someText1'},
{'title': 'someTitle2', 'text': 'someText2'},
{'title': 'someTitle3', 'text': 'someText3'}
];
NoteInheritedWidget(Widget child) : super(child: child);
static NoteInheritedWidget of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<NoteInheritedWidget>();
}
#override
bool updateShouldNotify(NoteInheritedWidget old) {
return old.notes != notes;
}
}
Home screen after add a note :
HomeScreen
List of notes printed in console after add a note :
I/flutter (18079): [{title: someTitle1, text: someText1}, {title: someTitle2, text: someText2}, {title: someTitle3, text: someText3}, {title: NewAddNoteTitle, text: NewAddNoteText}]
I'm using Android Studio and a real device instead an emulator.
I can't find the error and if you have another way to do this 'update' please show me.
I found a solution using the onPressed method as async and then an empty setState, is there any problem for the code doing this?
code:
child: ListTile(
onTap: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => NotePage(noteMode: NoteMode.Editing, index: index))
);
setState(() {});
print(_notes);
},
...
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => NotePage(noteMode: NoteMode.Adding))
);
setState(() {});
print(_notes.length);
print(_notes);
},
What is the best why to navigate to a page in flutter using the default Material Drawer.
I'm still learning how to work with Flutter.
In Android we used to anvigate to a fragment page, but how does this work in Flutter ?
I just want to understand how to navigate to an drawer item without without using bloc's.
class MdDrawer extends StatelessWidget {
final String title;
MdDrawer({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text('MyPage'),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: const Text(_AccountName),
accountEmail: const Text(_AccountEmail),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.brown,
child: Text(_AccountAbbr),
),
),
ListTile(
leading: Icon(Icons.lightbulb_outline),
title: Text('Notes'),
onTap: () => _alertOnListTileTap(context),
),
Divider(),
...
],
),
),
);
}
_alertOnListTileTap(BuildContext context) {
Navigator.of(context).pop();
showDialog(
context: context,
child: AlertDialog(
title: const Text('Not Implemented'),
actions: <Widget>[
FlatButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
),
);
}
}
Doing this without using bloc will make your code difficult to manage as it scales unless you just need an app prototype without any business logic.
Nonetheless, you can do it without bloc as follows;
Place all you screen in the body: as a list which displays the appropriate screen by indexing. like
body: [
Expenses(),
Inspiration()
Personal(),
Work(),
More(),
].elementAt(selectedIndex),
drawer: MdDrawer(onTap: (int val){
setState(() {
this._selectedIndex=val;
});
}
,)
Now you can push the desired body to display by providing the index as the return value of the Navigator.of(context).pop(index) or a callback function into MdDrawer. We will to do the callback function method. The index return will be used to update the state using setState.
class MdDrawer extends StatelessWidget {
final String title; final Function onTap;
MdDrawer({Key key, this.title, this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text('MyPage'),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
UserAccountsDrawerHeader(
accountName: const Text(_AccountName),
accountEmail: const Text(_AccountEmail),
currentAccountPicture: CircleAvatar(
backgroundColor: Colors.brown,
child: Text(_AccountAbbr),
),
),
ListTile(
leading: Icon(Icons.lightbulb_outline),
title: Text('Notes'),
onTap: () => _alertOnListTileTap(context, 0),
),
ListTile(
leading: Icon(Icons.lightbulb_outline),
title: Text('Expenses'),
onTap: () => _alertOnListTileTap(context, 1),
),
Divider(),
...
],
),
),
);
}
_alertOnListTileTap(BuildContext context, int index ) {
onTap(indext);
Navigator.of(context).pop();
}
}
I hope this helps
I have used this bottom navigation bar library in my app and it works perfectly. But i want to maintain a back navigation with the back button in android phones like for example in the Google Play Store bottom navigation where if we navigate through the bottom navigation the animation changes and also if we navigate back through the back button the animation changes the way before.
I have tried this article which is somewhat doing what i want but the animations are not working.
This is my stateful widget where my bottom nav bar is,
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentIndex;
final PageStorageBucket bucket = PageStorageBucket();
#override
void initState() {
// TODO: implement initState
super.initState();
currentIndex = 0;
}
void changePage(int index) {
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade300,
resizeToAvoidBottomInset : false,
body:
new Stack(
children: <Widget>[
new Offstage(
offstage: currentIndex != 0,
child: new TickerMode(
enabled: currentIndex == 0,
child: new MaterialApp(home: new HomePage()),
),
),
new Offstage(
offstage: currentIndex != 1,
child: new TickerMode(
enabled: currentIndex == 1,
child: new MaterialApp(home: new StayPage()),
),
),
new Offstage(
offstage: currentIndex != 2,
child: new TickerMode(
enabled: currentIndex == 2,
child: new MaterialApp(home: new TravelPage()),
),
),
new Offstage(
offstage: currentIndex != 3,
child: new TickerMode(
enabled: currentIndex == 3,
child: new MaterialApp(home: new MorePage()),
),
),
],
),
floatingActionButton: Visibility(
visible: _isVisible,
child: Container(
height: 100.0,
width: 85.0,
// margin: EdgeInsets.only(bottom: 5.0),
child: FittedBox(
child: FloatingActionButton.extended(
onPressed: () {
setState(() {});
},
elevation: 20.0,
icon: Icon(Icons.add),
label: Text(
"Plan",
style: TextStyle(
fontFamily: "OpenSansBold",
),
),
backgroundColor: Colors.red,
),
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
bottomNavigationBar: Visibility(
visible: _isVisible,
child: BubbleBottomBar(
hasInk: true,
fabLocation: BubbleBottomBarFabLocation.end,
opacity: .2,
currentIndex: currentIndex,
onTap: changePage,
elevation: 15,
items: <BubbleBottomBarItem>[
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(
Icons.home,
color: Colors.black,
),
activeIcon: Icon(
Icons.home,
color: Colors.red,
),
title: Text(
"Home",
style: TextStyle(
fontFamily: "OpenSans",
),
)),
BubbleBottomBarItem(
backgroundColor: Colors.deepPurple,
icon: Icon(
Icons.hotel,
color: Colors.black,
),
activeIcon: Icon(
Icons.hotel,
color: Colors.deepPurple,
),
title: Text(
"Stay",
style: TextStyle(
fontFamily: "OpenSans",
),
),
),
BubbleBottomBarItem(
backgroundColor: Colors.indigo,
icon: Icon(
Icons.card_travel,
color: Colors.black,
),
activeIcon: Icon(
Icons.card_travel,
color: Colors.indigo,
),
title: Text(
"Travel",
style: TextStyle(
fontFamily: "OpenSans",
),
),
),
BubbleBottomBarItem(
backgroundColor: Colors.green,
icon: Icon(
Icons.more,
color: Colors.black,
),
activeIcon: Icon(
Icons.more,
color: Colors.green,
),
title: Text(
"More",
style: TextStyle(
fontFamily: "OpenSans",
),
),
),
],
),
),
);
}
}
It is not necessary that i have to use this library, i just want to implement a bottom navigation bar and when navigating back through using the android back button the animations must work.
Any kind of help would be appreciated! Thanks!
Solved my problem. I used the medium post by Swav Kulinski which i pointed out in my question earlier.
The code is as follows,
class NavBar extends StatefulWidget {
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
final navigatorKey = GlobalKey<NavigatorState>();
int currentIndex;
final PageStorageBucket bucket = PageStorageBucket();
#override
void initState() {
// TODO: implement initState
super.initState();
currentIndex = 0;
}
void changePage(int index) {
navigatorKey.currentState.pushNamed(pagesRouteFactories.keys.toList()[index]);
setState(() {
currentIndex = index;
});
}
Future<bool> _onWillPop() {
if(currentIndex == 3){
changePage(2);
} else if(currentIndex == 2){
changePage(1);
} else if(currentIndex == 1){
changePage(0);
} else if(currentIndex == 0){
return Future.value(false);
}
return Future.value(true);
}
final pagesRouteFactories = {
"/": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("HomePage",style: Theme.of(context).textTheme.body1,),
),
),
"takeOff": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("Take Off",style: Theme.of(context).textTheme.body1,),
),
),
"landing": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("Landing",style: Theme.of(context).textTheme.body1,),
),
),
"settings": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("Settings",style: Theme.of(context).textTheme.body1,),
),
),
};
#override
Widget build(BuildContext context) {
return MaterialApp(
home: WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
body: _buildBody(),
bottomNavigationBar: _buildBottomNavigationBar(context),
),
),
);
}
Widget _buildBody() =>
MaterialApp(
navigatorKey: navigatorKey,
onGenerateRoute: (route) => pagesRouteFactories[route.name]()
);
Widget _buildBottomNavigationBar(context) => BottomNavigationBar(
items: [
_buildBottomNavigationBarItem("Home", Icons.home),
_buildBottomNavigationBarItem("Take Off", Icons.flight_takeoff),
_buildBottomNavigationBarItem("Landing", Icons.flight_land),
_buildBottomNavigationBarItem("Settings", Icons.settings)
],
currentIndex: currentIndex,
onTap: changePage,
);
_buildBottomNavigationBarItem(name, icon) => BottomNavigationBarItem(
icon: Icon(icon),
title: Text(name),
backgroundColor: Colors.black45,
activeIcon: Icon(icon)
);
}
I do not know if this is the right approach though. If anyone want to suggest me better option please let me know.