Why doesn't BottomNavigatorBarItem currentIndex get updated? - flutter

I am new to flutter and I did find similar questions on SO but am too novice to understand the nuance so apologies if this question is too similar to an already asked one.
I have a BottomNavigationBar which has 3 icons (Home, Play and Create) which should navigate between these 3 routes/pages.
main.dart
routes: {
"/home": (context) => MyHomePage(title: "STFU"),
"/play": (context) => Play(),
"/create": (context) => Create(),
"/settings": (context) => Settings(),
},
I extracted my navbar into a custom class so my 3 separate pages could use it:
bottom-nav.dart
class MyBottomNavBar extends StatefulWidget {
MyBottomNavBar({
Key? key,
}) : super(key: key);
#override
State<MyBottomNavBar> createState() => _MyBottomNavBarState();
}
class _MyBottomNavBarState extends State<MyBottomNavBar> {
int _selectedIndex = 0;
void _onTapped(int index) => {
print("_onTapped called with index = $index"),
setState(
() => _selectedIndex = index,
)
};
#override
Widget build(BuildContext context) {
return BottomNavigationBar(
backgroundColor: Colors.orangeAccent[100],
currentIndex: _selectedIndex,
onTap: (value) => {
print("value is $value"),
// find index and push that
_onTapped(value),
if (value == 0)
{Navigator.pushNamed(context, "/home")}
else if (value == 1)
{Navigator.pushNamed(context, "/play")}
else if (value == 2)
{Navigator.pushNamed(context, "/create")}
},
items: [
BottomNavigationBarItem(label: "Home", icon: Icon(Icons.home_filled)),
BottomNavigationBarItem(
label: "Play", icon: Icon(Icons.play_arrow_rounded)),
BottomNavigationBarItem(label: "Create", icon: Icon(Icons.create)),
],
);
}
}
so now i just set this MyBottomNavBar class to the bottomNavigationBar property of the Scaffold widget my inside Home page, Play page and Create page for eg.
home.dart
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Column(
children: [
Container(
padding: EdgeInsets.all(20.00),
child: Text("inside home"),
),
],
),
bottomNavigationBar: MyBottomNavBar(),
);
}
}
play.dart
class Play extends StatefulWidget {
const Play({super.key});
#override
State<Play> createState() => _PlayState();
}
class _PlayState extends State<Play> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text("inside play page"),
SizedBox(
height: 30.00,
),
Text("some text"),
],
),
),
bottomNavigationBar: MyBottomNavBar(),
);
}
}
The nav bar buttons work to switch between pages but for some reason the currentIndex value isn't getting updated and stays at 0 (i.e on the "Home" icon). When I debug it I can see _selectedIndex getting updated inside inside the _onTapped function which should update the currentIndex value but it doesn't appear to do so. Any help would be appreciated

What you have here is three different pages with their separate BottomNavBar class instance. Instead you should have a shared Scaffold and one bottomNavBar so that when you navigate bottomNavbar state does not reset.
You can use PageView to do this.
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
List<Widget> pages = const [Home(), Play(), Create()];
final _pageController = PageController();
int _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _selectedIndex,
onTap: (index) {
_pageController.jumpToPage(index);
_selectedIndex = index;
setState(() {});
},
items: const [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
BottomNavigationBarItem(icon: Icon(Icons.play_arrow), label: 'Play'),
BottomNavigationBarItem(icon: Icon(Icons.create), label: 'Create'),
],
backgroundColor: Colors.greenAccent,
),
body: PageView(
controller: _pageController,
children: pages,
),
);
}
}
class Home extends StatelessWidget {
const Home({super.key});
#override
Widget build(BuildContext context) {
return const Placeholder();
}
}
class Play extends StatelessWidget {
const Play({super.key});
#override
Widget build(BuildContext context) {
return const Placeholder();
}
}
class Create extends StatelessWidget {
const Create({super.key});
#override
Widget build(BuildContext context) {
return const Placeholder();
}
}

Related

Preserve state of widget in flutter even though parent widget rebuilds

I'm trying to preserve the state of widget pages when switching between widgets using BottomNavigationBar. I've read here that I can do this using IndexedStack, however, that doesn't work in my case for two reasons:
The Scaffold in which the pages are displayed gets rebuilt when switching between pages because for some, but not all, pages the Scaffold should be extended: Scaffold( extendBody: _pageIndex == 1, ...)
The pages should be built for the first time just when the page is opened for the first time and not right from the start
Here's a small example that shows that IndexStack is not working as intended because the Scaffold rebuilds:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _pageIndex = 1;
List<Widget> _pages = [Text("hi"), Counter()];
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: _pageIndex == 1,
appBar: AppBar(),
body: IndexedStack(
children: _pages,
index: _pageIndex,
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Goto 0',),
BottomNavigationBarItem(icon: Icon(Icons.business), label: 'Goto 1',),
],
currentIndex: _pageIndex,
onTap: (int index) {
setState(() {
_pageIndex = index;
});
print("idx " + _pageIndex.toString());
},
),
);
}
}
Demo showing that the state is not preserved
This is the Counter which can be replaced by any other stateful widget:
class Counter extends StatefulWidget {
#override
_CounterState createState() => _CounterState();
}
//this part is not important, just to show that state is lost
class _CounterState extends State<Counter> {
int _count = 0;
#override
void initState() {
_count = 0;
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: TextButton(
child: Text("Count: " + _count.toString(), style: TextStyle(fontSize: 20),),
onPressed: () {
setState(() {
_count++;
});
},
),
);
}
}
First off, great question! The trick is to use KeyedSubtree, and conditionally render pages depending on if they have been visited yet or not.
You could adapt your code this way to achieve your desired behavior:
class Page {
const Page(this.subtreeKey, {required this.child});
final GlobalKey subtreeKey;
final Widget child;
}
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
var _pageIndex = 1;
final _pages = [
Page(GlobalKey(), child: Text('Hi')),
Page(GlobalKey(), child: Counter()),
];
final _builtPages = List<bool>.generate(2, (_) => false);
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: _pageIndex == 1,
appBar: AppBar(),
body: Stack(
fit: StackFit.expand,
children: _pages.map(
(page) {
return _buildPage(
_pages.indexOf(page),
page,
);
},
).toList(),
),
bottomNavigationBar: BottomNavigationBar(
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Goto 0',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'Goto 1',
),
],
currentIndex: _pageIndex,
onTap: (int index) {
setState(() {
_pageIndex = index;
});
print("idx " + _pageIndex.toString());
},
),
);
}
Widget _buildPage(
int tabIndex,
Page page,
) {
final isCurrentlySelected = tabIndex == _pageIndex;
_builtPages[tabIndex] = isCurrentlySelected || _builtPages[tabIndex];
final Widget view = KeyedSubtree(
key: page.subtreeKey,
child: _builtPages[tabIndex] ? page.child : Container(),
);
if (tabIndex == _pageIndex) {
return view;
} else {
return Offstage(child: view);
}
}
}
You should be able to modify this code to add more tabs, functionality, etc.

Flutter Setstate called multiple times (GestureDetector & PageView)

basically I have a swiping screen with elements, where user is able to swipe in left or right direction. When the user is swiping, im calling some functions. Im using GestureDetector for gesture recognitions and PageView.Custom for my items. Probably ListView.Custom does also work, but it doesn't fix my issue I have.
I need a PageController, because I have to control the navigation programatically. And I think the PageController maybe is the reason behind my issue that my functions are called multiple times. How to fix it? Does somebody know why setstate is called that often and what to do to prevent it?
Im providing you a fully working example (minified version) with a print on the swiping right actions, where you can see that its beeing called multiple times.
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentIndex = 0;
#override
Widget build(BuildContext context) {
// Page selector for tab list
void _selectPage(int index) {
print('page index: $index');
setState(() {
currentIndex = index;
});
}
// Routes list for tab navigation Android
final List<Widget> _pages = [
ScreenA(),
ScreenB(func: _selectPage),
];
return Scaffold(
appBar: AppBar(),
body: _pages[currentIndex],
bottomNavigationBar: SafeArea(
child: BottomNavigationBar(
onTap: _selectPage,
iconSize: 22,
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.description),
label: 'ScreenA',
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.ac_unit_outlined),
label: 'ScreenB'),
],
),
),
);
}
}
class ScreenA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Text('HOME'),
);
}
}
class ScreenB extends StatefulWidget {
Function func;
ScreenB({Key key, #required this.func})
: super(key: key);
#override
_ScreenBState createState() => _ScreenBState();
}
class _ScreenBState extends State<ScreenB> {
_ScreenBState();
var _controller = PageController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.access_alarm_sharp),
onPressed: () async {
widget.func(0);
},
),
],
),
body: PageView.custom(
dragStartBehavior: DragStartBehavior.start,
controller: _controller,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
childrenDelegate: SliverChildBuilderDelegate((ctx, pageIndex) =>
GestureDetector(
onPanUpdate: (details) async {
if (details.delta.dx < 0) {
_controller.nextPage(
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut);
print('function called');
}
},
child: Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: Text('hi')))))),
);
}
}
Thanks in advance!
The problem is that you are using the onPanUpdate method, which is triggered every time a user drags their finger either right or left. You should use the onPanEnd method, which is only triggered when the user's finger is off the screen after dragging either left or right. The function below will work fine.
onPanEnd: (details) async { if (details.velocity.pixelsPerSecond.dx < 0) { _controller.nextPage( duration: Duration(milliseconds: 200), curve: Curves.easeInOut); print('function called'); } }
Please write this function out of widget build function
// Page selector for tab list
void _selectPage(int index) {
print('page index: $index');
setState(() {
currentIndex = index;
});
}
like this
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentIndex = 0;
// Page selector for tab list
void _selectPage(int index) {
print('page index: $index');
setState(() {
currentIndex = index;
});
}
// Routes list for tab navigation Android
final List<Widget> _pages = [
ScreenA(),
ScreenB(func: _selectPage),
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: _pages[currentIndex],
bottomNavigationBar: SafeArea(
child: BottomNavigationBar(
onTap: _selectPage,
iconSize: 22,
currentIndex: currentIndex,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.description),
label: 'ScreenA',
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.ac_unit_outlined),
label: 'ScreenB'),
],
),
),
);
}
}
class ScreenA extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
child: Text('HOME'),
);
}
}
class ScreenB extends StatefulWidget {
Function func;
ScreenB({Key key, #required this.func})
: super(key: key);
#override
_ScreenBState createState() => _ScreenBState();
}
class _ScreenBState extends State<ScreenB> {
_ScreenBState();
var _controller = PageController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(Icons.access_alarm_sharp),
onPressed: () async {
widget.func(0);
},
),
],
),
body: PageView.custom(
dragStartBehavior: DragStartBehavior.start,
controller: _controller,
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
childrenDelegate: SliverChildBuilderDelegate((ctx, pageIndex) =>
GestureDetector(
onPanUpdate: (details) async {
if (details.delta.dx < 0) {
_controller.nextPage(
duration: Duration(milliseconds: 200),
curve: Curves.easeInOut);
print('function called');
}
},
child: Center(
child: Container(
width: 200,
height: 200,
color: Colors.red,
child: Text('hi')))))),
);
}
}

Screen navigation in flutter

Update:
The app has two stateful widget screens: Home, and Search. Both screens have search boxes and a bottom navigation.
The problem that needs to be solved is when a user taps the search box at the top of the home screen, the app should take them to the search screen without hiding the bottom navigation (just like what the eBay app does).
I have tried calling the Search class when the user taps the search box on the Home screen. And this approach works. However, the new screen hides the navigation bar at the bottom.
The following code handles the navigation between screens.
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int _currentIndex = 0;
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Navigator(
key: _navigatorKey,
onGenerateRoute: (RouteSettings settings) {
switch (settings.name) {
case 'Search':
return MaterialPageRoute(builder: (context) => Search());
default:
return MaterialPageRoute(builder: (context) => UserHome());
}
}),
bottomNavigationBar: BottomNavigationBar(
onTap: _onTap,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text('Home'))
BottomNavigationBarItem(icon: Icon(Icons.search), title: Text('Search'))
],
),
);
}
void _onTap(int tappedIndex) {
setState(() => _currentIndex = tappedIndex);
switch (tappedIndex) {
case 0:
_navigatorKey.currentState.pushReplacementNamed('Home');
break;
case 1:
_navigatorKey.currentState.pushReplacementNamed('Search');
break;
}
}
}
If you are trying to do this for automated testing. You can do so using widget testing. Widget tests in flutter can simulate button taps and check for the expected output
class TestPage extends StatefulWidget {
#override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
bool home;
#override
void initState() {
super.initState();
home = true;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: home ? UserHome() : Search(),
bottomNavigationBar: BottomNavigationBar(
onTap: _onTap,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), title: Text('Home')),
BottomNavigationBarItem(
icon: Icon(Icons.search), title: Text('Search'))
],
),
);
}
void _onTap(int tappedIndex) {
setState(() {
if (tappedIndex == 0) {
home = true;
} else {
home = false;
}
});
}
}
class UserHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Center(
child: Container(
color: Colors.yellow,
child: Text('USER HOME'),
),
)
],
);
}
}
class Search extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Center(
child: Container(
color: Colors.green,
child: Text('SEARCH'),
),
)
],
);
}
}
I know this is not exactly very similar to your initial solution but it achieves the behavior you intend.

Flutter - How to change index of BottomNavigationBar if NavigationBar is not visible?

This is my setup:
Home.dart
final List<Widget> _pages = [
Screen1(),
Screen2(),
Screen3(),
Screen4(),
];
int _selectedPageIndex = 0;
void _selectPage(int index) {
setState(() {
_selectedPageIndex = index;
});}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
body: _pages[_selectedPageIndex],
bottomNavigationBar: _selectedPageIndex != 2
? Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
...
Now when we navigate to Screen3() I'm hiding the complete BottomNavigationBar and show the Screen in Fullscreen. With a button I want to navigate back to any other position. How to do this? I don't want to use any Routes to close. How can we access _selectedPageIndex or do you have another good idea?
Would appreciate any ideas.
You can copy paste run full code below
Step 1: keep previous index, needed when go back from full screen page
void _onItemTapped(int index) {
setState(() {
_previousIndex = _selectedPageIndex;
_selectedPageIndex = index;
});
}
Step 2: pass refresh() callback to full screen page here is Setting()
void refresh() {
setState(() {
_selectedPageIndex = _previousIndex;
});
}
...
case 2:
{
print("settings");
return Settings(
callback: refresh,
);
}
Step 3: In full screen page's Raised Button call this callback
RaisedButton(
onPressed: () {
widget.callback();
},
child: Text("Go back"),
)
working demo
full code
import 'package:flutter/material.dart';
void main() => 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 _selectedPageIndex = 0;
int _previousIndex = 0;
void refresh() {
setState(() {
_selectedPageIndex = _previousIndex;
});
}
void _onItemTapped(int index) {
setState(() {
_previousIndex = _selectedPageIndex;
_selectedPageIndex = index;
});
}
Widget pageCaller(int index) {
print(index);
switch (index) {
case 0:
{
return Category();
}
case 1:
{
return Feed();
}
case 2:
{
print("settings");
return Settings(
callback: refresh,
);
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home'),
),
body: Center(
child: pageCaller(_selectedPageIndex),
),
bottomNavigationBar: _selectedPageIndex == 2
? null
: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('Category'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
title: Text('Feed'),
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
title: Text('Settings'),
),
],
currentIndex: _selectedPageIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}
class Category extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Category"),
),
);
}
}
class Feed extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text("Feed"),
),
);
}
}
class Settings extends StatefulWidget {
VoidCallback callback;
Settings({this.callback});
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text("This is setting page"),
RaisedButton(
onPressed: () {
widget.callback();
},
child: Text("Go back"),
),
],
));
}
}

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'),
),
);
}
}