MaterialPageRoute goes to a new page without the appbar using it with bottomNavigationBar - flutter

I have an app with three routes and uses the bottomNavigationBar to navigate between them. In one of the routes I have a button in the page that will also navigate to one of the pages.
Heres my main page
import 'package:flutter/material.dart';
import 'page_two.dart';
import 'page_three.dart';
void main() {
return runApp(MyApp());
}
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
List<Widget> _widgetOptions = <Widget>[
Text('Main'),
PageTwo(),
PageThree(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home, color: Colors.black),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
Page Two
import 'package:flutter/material.dart';
import 'main.dart';
class PageTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
},
),
);
}
}
and Page Three with a button that navigates to page two
import 'package:flutter/material.dart';
import 'page_two.dart';
class PageThree extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageTwo()),
);
},
),
);
}
}
When I press the button on Page Three, it will go to Page Two without the AppBar and the BottomNavigationBar

Use GlobalKey and In PageTwo Widget call MyStatefulWidgetState's _onItemTapped function
You can see working demo and full code below
code snippet
final scakey = new GlobalKey<_MyStatefulWidgetState>();
...
child: Text('Go page 2'),
onPressed: () {
scakey.currentState._onItemTapped(1);
full code
import 'package:flutter/material.dart';
void main() {
return runApp(MyApp());
}
final scakey = new GlobalKey<_MyStatefulWidgetState>();
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(key: scakey),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
#override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
final myKey = new GlobalKey<_MyStatefulWidgetState>();
List<Widget> _widgetOptions = <Widget>[
Text('Main'),
PageTwo(),
PageThree(),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: myKey,
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home, color: Colors.black),
title: Text('Home'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business, color: Colors.black),
title: Text('Business'),
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
class PageTwo extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 1'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => MyApp()),
);
},
),
);
}
}
class PageThree extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: RaisedButton(
child: Text('Go page 2'),
onPressed: () {
scakey.currentState._onItemTapped(1);
/*Navigator.push(
context,
MaterialPageRoute(builder: (context) => PageTwo()),
);*/
},
),
);
}
}

When using navigation bar to navigate between pages, you are tapping on BottomNavigationBarItem to change the index by calling setState() and as the result, build method is triggered with a new _selectedIndex and that index is used to render your appropriate widget.
_widgetOptions.elementAt(_selectedIndex)
Navigator.push on the other hand is just pushing a new route on top of the navigation stack. You are not getting an AppBar or BottomNavigationBar since you don't have them on PageTwo. What I would recommend you is to create a callback function in PageTwo and call that function on button tap. You can now use that callback in MyStatefulWidget to change the index with setState. Here is an example
Declare a final like below in your pages.
final void Function(int index) pageChanged;
In the onTap event of your button, call this function.
widget.pageChanged(1); // PageTwo
In MyStatefulWidget, when you are creating pages, pass the function.
PageTwo(pageChanged:(index){
setState(){_selectedIndex = index;}
});

Related

How to use bottomNavigationBar in a separate file?

I have the following code that is working properly:
import 'package:flutter/material.dart';
import 'screen_curiosities.dart';
import 'screen_movies.dart';
import 'screen_releases.dart';
import '../utils/side_menu.dart';
import '../utils/bottom_menu.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int selectedIndex = 0;
List screens = [
ScreenMovies(),
ScreenReleases(),
ScreenCuriosities()
];
void onClicked(int index) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Movies'),
backgroundColor: Colors.black,
),
body: Center(
child: screens.elementAt(selectedIndex),
),
drawer: SideMenu(),
bottomNavigationBar: BottomNavigationBar(
items:[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Movies',
),
BottomNavigationBarItem(
icon: Icon(Icons.new_releases),
label: 'Releases',
),
BottomNavigationBarItem(
icon: Icon(Icons.question_answer),
label: 'Curiosities',
)
],
currentIndex: selectedIndex,
onTap: onClicked,
selectedItemColor: Colors.red[800],
backgroundColor: Colors.black,
unselectedItemColor: Colors.white,
)
);
}
}
Now I am trying to separate the Widget BottomNavigationBar to another file and call him on the property "bottomNavigationBar" from Scaffold. It would be like this:
bottomNavigationBar: BottomMenu()
I did it with the Widget Drawer and it worked, but when I tried the same thing with bottomNavigationBar it wasn't successful.
When I try to use the variable selectedIndex in the new Widget it is always undefined.
I tried many things, but I couldn't solve this. Is there any way to use the Widget bottomNavigationBar in a separated file?
EDIT
Below, follow the 2 files that I need to make this link from the menu to the page in order to make them work together:
file home.dart
import 'package:flutter/material.dart';
import 'screen_curiosities.dart';
import 'screen_movies.dart';
import 'screen_releases.dart';
import '../utils/side_menu.dart';
import '../utils/bottom_menu.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int selectedIndex = 0;
List screens = [
ScreenMovies(),
ScreenReleases(),
ScreenCuriosities()
];
void onClicked(int index) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Movies'),
backgroundColor: Colors.black,
),
body: Center(
child: screens.elementAt(selectedIndex),
),
drawer: SideMenu(),
bottomNavigationBar: BottomMenu() // Using the Widget here
}
}
file bottom_menu.dart
import 'package:flutter/material.dart';
class BottomMenu extends StatelessWidget {
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
items:[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Movies',
),
BottomNavigationBarItem(
icon: Icon(Icons.new_releases),
label: 'Releases',
),
BottomNavigationBarItem(
icon: Icon(Icons.question_answer),
label: 'Curiosities',
)
],
currentIndex: selectedIndex, // the variable is undefined
onTap: onClicked, // the function is undefined
selectedItemColor: Colors.red[800],
backgroundColor: Colors.black,
unselectedItemColor: Colors.white,
);
}
}
You can copy paste run two full code below
You can pass selectedIndex and onClicked to BottomMenu
code snippet
bottomNavigationBar: BottomMenu(
selectedIndex: selectedIndex,
onClicked: onClicked,
));
...
class BottomMenu extends StatelessWidget {
final selectedIndex;
ValueChanged<int> onClicked;
BottomMenu({this.selectedIndex, this.onClicked});
working demo
full code main.dart
import 'package:flutter/material.dart';
import 'bottom.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int selectedIndex = 0;
List screens = [ScreenMovies(), ScreenReleases(), ScreenCuriosities()];
void onClicked(int index) {
setState(() {
selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Movies'),
backgroundColor: Colors.black,
),
body: Center(
child: screens.elementAt(selectedIndex),
),
//drawer: SideMenu(),
bottomNavigationBar: BottomMenu(
selectedIndex: selectedIndex,
onClicked: onClicked,
));
}
}
class ScreenMovies extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text("ScreenMovies"),
);
}
}
class ScreenReleases extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text("ScreenReleases"),
);
}
}
class ScreenCuriosities extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Center(
child: Text("ScreenCuriosities"),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Home(),
);
}
}
full code bottom.dart
import 'package:flutter/material.dart';
class BottomMenu extends StatelessWidget {
final selectedIndex;
ValueChanged<int> onClicked;
BottomMenu({this.selectedIndex, this.onClicked});
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Movies',
),
BottomNavigationBarItem(
icon: Icon(Icons.new_releases),
label: 'Releases',
),
BottomNavigationBarItem(
icon: Icon(Icons.question_answer),
label: 'Curiosities',
)
],
currentIndex: selectedIndex,
onTap: onClicked,
selectedItemColor: Colors.red[800],
backgroundColor: Colors.black,
unselectedItemColor: Colors.white,
);
}
}

how to change properties of list tile from its onTap() function in flutter?

leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
// There I want to change title, background color etc
},
),
title: Text('title'),
dense: false,
),
I want to change properties of list tile from its own onTap()
You can copy paste run full code below
You can use StatefulWidget and call setState inside onTap
code snippet
class _ListTileCustomState extends State<ListTileCustom> {
String _title = "title";
Color _color = Colors.blue;
#override
Widget build(BuildContext context) {
return ListTile(
tileColor: _color,
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState(() {
_title = "changed";
_color = Colors.red;
});
},
child: Icon(Icons.add)),
title: Text(_title),
dense: false,
);
}
}
working demo
full code
import 'package:flutter/material.dart';
class ListTileCustom extends StatefulWidget {
#override
_ListTileCustomState createState() => _ListTileCustomState();
}
class _ListTileCustomState extends State<ListTileCustom> {
String _title = "title";
Color _color = Colors.blue;
#override
Widget build(BuildContext context) {
return ListTile(
tileColor: _color,
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState(() {
_title = "changed";
_color = Colors.red;
});
},
child: Icon(Icons.add)),
title: Text(_title),
dense: false,
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
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 _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ListTileCustom(),
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
you can define one variable before build a method and use that variable to the title of listtile and when you ontap then change the state using setState and It will change the title of your listtie.
leading: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
setState((){
title="your text"
});
},
),
title: Text(title),
dense: false,
),
here title is variable
and ListTile also has property of onTap

Flutter: value of currentIndex property in BottomNavigationBar doesn't update when the state updates

I have a BottomNavigationBar that navigates to other pages when pressing an icon. This works fine, except the value of the currentIndex property in BottomNavigationBar doesn't update when the state updates, which means there is no change on the acual BottomNavigationBar. enter image description here
I'm using a vaiable (_selectedPage) to keep track of the selected index in the BottomNavigationBar, and the value changes when tapping an item, but it's not updating the currentIndex property when the state updates.. why is that?
import 'package:flutter/material.dart';
import 'package:independentproject/pages/home_page.dart';
import 'package:independentproject/pages/cook_recipe.dart';
class PageNavigationBar extends StatefulWidget {
#override
_PageNavigationBarState createState() => _PageNavigationBarState();
}
class _PageNavigationBarState extends State<PageNavigationBar> {
//default page showing in bottom navigation bar will be CookRecipe()
int _selectedPage = 1;
//all pages optional in bottom navigation bar
final List<Widget> _pageOptions = [
HomePage(),
CookRecipe(),
];
void onTapped(int pageTapped) {
setState(() {
//print(pageTapped);
_selectedPage = pageTapped;
Navigator.push(context, MaterialPageRoute(builder: (context) => _pageOptions[pageTapped]));
//print(_selectedPage);
});
}
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
//TODO: currentIndex: doesn't update when the state updates, why?
currentIndex: _selectedPage,
//items showing in bottom navigation bar
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Homepage'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search recipe'),
),
],
onTap: (int pageTapped) {
onTapped(pageTapped);
},
);
}
}
import 'package:flutter/material.dart';
import 'package:independentproject/page_navigation_bar.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Home page'),
),
body: Center(
child: Text('Home page'),
),
bottomNavigationBar: PageNavigationBar(),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:independentproject/page_navigation_bar.dart';
class CookRecipe extends StatefulWidget {
#override
_CookRecipeState createState() => _CookRecipeState();
}
class _CookRecipeState extends State<CookRecipe> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Search recipe'),
),
body: Center(
child: Text('Search recipes'),
),
bottomNavigationBar: PageNavigationBar(),
),
);
}
}
I would advise you to create a widget that will contain the BottomNavigationBar and also PageView that would allow you to switch pages with PageController.
For example:
class _MainScreenState extends State<MainScreen> {
PageController _pageController;
int _page = 1;
Duration pageChanging = Duration(milliseconds: 300);//this is for page animation-not necessary
Curve animationCurve = Curves.linear;//this is for page animation-not necessary
_MainScreenState();
#override
void initState() {
super.initState();
_pageController = PageController(initialPage: 1);
}
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
controller: _pageController,
onPageChanged: onPageChanged,
children: <Widget>[
//here are all the pages you need:
//CookRecipe(),
],
),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(
Icons.message,
),
title: Container(height: 0.0),
),
BottomNavigationBarItem(
icon: Icon(
Icons.home,
),
title: Container(height: 0.0),
),
BottomNavigationBarItem(
icon: Icon(
Icons.person,
),
title: Container(height: 0.0),
),
],
onTap: navigationTapped,
selectedItemColor: Theme.of(context).backgroundColor,
currentIndex: _page,
),
),
);
}
void navigationTapped(int page) {
_pageController.animateToPage(page,duration: pageChanging,
curve: animationCurve,);
}
#override
void dispose() {
super.dispose();
_pageController.dispose();
}
void onPageChanged(int page) {
if (this.mounted){
setState(() {
this._page = page;
});
}}
You can also do this without the PageView,and use only the controller to switch pages.
BTW-you create new instance of the navigation bar when you load a page which is bad practice
it is because PageNavigationBar is a own class, when you call there a setstate only this class updates
take a look at the Provider
a very usefull state management Package
or you can also handle your Page, when the NavBar is your Main Page and you have only one Page
return MaterialApp(
home: Scaffold(
appBar: ownAppBar(_selectedPage),
body: _bodyOptions[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedPage,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Homepage'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search recipe'),
),
],
onTap: (int pageTapped) {
onTapped(pageTapped);
},
)
),
);
final List<Widget> _bodyOptions = [
HomePage(),
CookRecipe(),
];
You don't need to use Navigator to change pages, I modified your code just try.
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(home: PageNavigationBar()));
}
class PageNavigationBar extends StatefulWidget {
#override
_PageNavigationBarState createState() => _PageNavigationBarState();
}
class _PageNavigationBarState extends State<PageNavigationBar> {
//default page showing in bottom navigation bar will be CookRecipe()
int _selectedPage = 1;
//all pages optional in bottom navigation bar
final List<Widget> _pageOptions = [
HomePage(),
CookRecipe(),
];
void onTapped(int pageTapped) {
setState(() {
//print(pageTapped);
_selectedPage = pageTapped;
// Navigator.push(context, MaterialPageRoute(builder: (context) => _pageOptions[pageTapped]));
//print(_selectedPage);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _pageOptions[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
//TODO: currentIndex: doesn't update when the state updates, why?
currentIndex: _selectedPage,
//items showing in bottom navigation bar
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Homepage'),
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
title: Text('Search recipe'),
),
],
onTap: (int pageTapped) {
onTapped(pageTapped);
},
),
);
}
}
class CookRecipe extends StatefulWidget {
#override
_CookRecipeState createState() => _CookRecipeState();
}
class _CookRecipeState extends State<CookRecipe> {
#override
Widget build(BuildContext context) {
return Center(
child: Text('Search recipes'),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Center(
child: Text('Home page'),
);
}
}

Is it possible for me to choose to show or hide bottom navigation bar when I move to new page with navigator in flutter?

everyone.
I'm making an app which has bottom navigation bar with two items, and each item has buttons to move new pages.
Let's say each of those item is called for A and B.
A has a button for moving to new Page C. C shows today's weather. And I want to see bottom navigation bar in C as well.
B also has a button for moving to new Page D. D is login page. And I don't want to see bottom navigation bar in D.
I tried to use IndexedStack and GlobalKey, and it did work for showing bottom navigation bar in C. But I failed to hide bottom navigation bar with it in D.
I also read many articles here and there but never worked.
Can anybody help me?
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _currentTab;
List<Widget> _tabList = [
FirstTab(),
SecondTab()
];
#override
void initState() {
super.initState();
_currentTab = 0;
}
void onItemTapped(int index) {
setState(() {
_currentTab = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _tabList[_currentTab],
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today),
title: Text('Weather')
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
title: Text('Login')
)
],
onTap: onItemTapped,
currentIndex: _currentTab,
),
);
}
}
class FirstTab extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => WeatherPage()));
},
child: Text('To see the weather today'),
),
),
);
}
}
class SecondTab extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => LoginPage()));
},
child: Text('To Login'),
),
),
);
}
}
class WeatherPage extends StatelessWidget { // This page needs bottom navigation bar
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Rainy'),
),
);
}
}
class LoginPage extends StatelessWidget { // There is no bottom navigation bar on this page
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Click to login'),
),
);
}
}
Edit:
Have a new bottomNavbar in the WeatherPage (first solution in comment section):
import 'package:flutter/material.dart';
class StackOverflow2 extends StatefulWidget {
#override
_StackOverflow2State createState() => _StackOverflow2State();
}
class _StackOverflow2State extends State<StackOverflow2> {
int _currentTab;
List<Widget> _tabList = [FirstTab(), SecondTab()];
#override
void initState() {
super.initState();
_currentTab = 0;
}
void onItemTapped(int index) {
setState(() {
_currentTab = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _tabList[_currentTab],
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today), title: Text('Weather')),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('Login'))
],
onTap: onItemTapped,
currentIndex: _currentTab,
),
);
}
}
class WeatherPage extends StatefulWidget {
// Th
#override
_WeatherPageState createState() => _WeatherPageState();
}
class _WeatherPageState extends State<WeatherPage> {
int _currentTab;
Widget myCenter = Center(
child: Text('Rainy'),
);
List<Widget> _tabList;
#override
void initState() {
super.initState();
_tabList = [myCenter, SecondTab()];
_currentTab = 0;
}
void onItemTapped(int index) {
setState(() {
_currentTab = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: _tabList[_currentTab],
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.calendar_today), title: Text('Weather')),
BottomNavigationBarItem(
icon: Icon(Icons.person), title: Text('Login'))
],
onTap: onItemTapped,
currentIndex: _currentTab,
),
);
}
}
class FirstTab extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => WeatherPage()));
},
child: Text('To see the weather today'),
),
),
);
}
}
class SecondTab extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => LoginPage()));
},
child: Text('To Login'),
),
),
);
}
}
class LoginPage extends StatelessWidget {
// There is no bottom navigation bar on this page
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Click to login'),
),
);
}
}

Showing BottonNavigatorBar on All Pages in Flutter

In my app I have two pages Page1 and Page2. I also have tab bar which is displayed at the bottom of the screen. The problem is that the TabBar goes away when I use Navigator.push from one of the pages. Check out the animations below:
Here is all my code:
void main() => runApp(App());
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Hello",
home: DefaultTabController(
length: 2,
child: Scaffold(
bottomNavigationBar: TabBar(tabs: <Widget>[
Tab(icon: Icon(Icons.directions_car)),
Tab(icon: Icon(Icons.do_not_disturb))
],
labelColor: Colors.black
)
,
body: TabBarView(children: <Widget>[
Page1(),
Page2()
])
)
)
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page 1'),
),
body: FlatButton(
child: Text('Go to Page 2'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return Page2();
}
));
},
color: Colors.orange
)
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Page 2'),
),
body: FlatButton(
child: Text('Go to Page 1'),
onPressed: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) {
return Page1();
}
));
},
color: Colors.purple
)
);
}
}
what you want can be easily done with the help of cupertino widgets.
Example Code:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() => runApp(MainPage());
class MainPage extends StatefulWidget {
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
int _currentIndex = 0;
#override
Widget build(BuildContext context) {
return CupertinoApp(
debugShowCheckedModeBanner: false,
title: 'Demo App',
home: CupertinoTabScaffold(
tabBar: CupertinoTabBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.event), title: Text("Tab 1")),
BottomNavigationBarItem(
icon: Icon(Icons.group), title: Text("Tab 2")),
],
currentIndex: _currentIndex,
onTap: (int) {
setState(() {
_currentIndex = int;
});
},
),
tabBuilder: (context, int) {
switch (int) {
case 0:
{
return CupertinoTabView(
builder: (context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Tab 1 Content'),
),
CupertinoButton.filled(
child: Text('Goto next Page in Tab1'),
onPressed: () {
Navigator.push(context,
CupertinoPageRoute(builder: (context) {
return Body(int);
}));
})
],
),
);
},
);
}
break;
case 1:
{
return CupertinoTabView(
builder: (context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('Tab 2 Content'),
),
CupertinoButton.filled(
child: Text('Goto next Page in Tab2'),
onPressed: () {
Navigator.push(context,
CupertinoPageRoute(builder: (context) {
return Body(int);
}));
})
],
),
);
},
);
}
break;
}
},
),
);
}
}
class Body extends StatefulWidget {
final int index;
Body(this.index);
#override
_BodyState createState() => _BodyState();
}
class _BodyState extends State<Body> {
#override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('Page2 of Tab${widget.index}'),
),
child: Center(
child: Container(
child: Text('Page 2'),
),
));
}
}
EDIT
Sorry I misunderstood the question, this may be a duplicate of Flutter: Keep BottomNavigationBar When Push to New Screen with Navigator
Original answer
Use a single master page and replace the body dynamically with each sub page (containing their own content) :
Example :
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// current page index of the bottom navigation bar
int _currentIndex = 0;
// update the state of the index on tab tap
void onTabTapped(int index) {
setState(() {
_currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
// list of pages of the bottom navigation bar
final List<Widget> _children = [
FirstPage(title: "My page 1"),
SecondPage(title: "My page 2"),
ThirdPage(title: "My page 3"),
];
return Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
title: Text(widget.title),
),
body: _children[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
onTap: onTabTapped,
currentIndex: _currentIndex,
type: BottomNavigationBarType.shifting,
items: [
BottomNavigationBarItem(icon: Icon(Icons.event), title: Text("Page 1")),
BottomNavigationBarItem(icon: Icon(Icons.group), title: Text("Page 2")),
BottomNavigationBarItem(icon: Icon(Icons.camera_alt), title: Text("Page 3")),
],
),
);
}
}
Then FirstPage, SecondPage, ThirdPage can content only their own content :
import 'package:flutter/material.dart';
class FirstPage extends StatefulWidget {
FirstPage({Key key, this.title}) : super(key: key);
final String title;
#override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: // your body content
);
}
}
Pushing a route will set the Widget as the child of the MaterialApp. Every screen should contain it's own scaffold with it's own BottonNavigatorBar.