Leave a rating/review
If you’re using Flutter 1.17 and above then you won’t get the Dart constraint error since those versions work a newer Dart sdk.
Tabs are very common is most modern apps and Flutter provides us with different tab based widgets. The Scaffold
widget provides us with the BottomNavigationBar
which let’s us add a widget that can be shown at the bottom of the screen. Let’s add a BottomNavigationBar
widget. Paste the following code inside the Scaffold:
...
bottomNavigationBar: BottomNavigationBar(
currentIndex: 0,
onTap: (int index) {},
items: [
const BottomNavigationBarItem(
label: 'Home',
icon: Icon(Icons.home),
),
const BottomNavigationBarItem(
label: 'Inbox',
icon: Icon(Icons.mail),
),
],
),
...
Save your work. The BottomNavigationBar
shows up with the home and inbox items. Here we set its currentIndex
to 0 which selects the first tab item as the active tab.
Next, we pass an empty function to the onTap
property. This function would be executed when a BottomNavigationBarItem
is clicked and it receives the clicked item’s index. We’ll implement this shorthly. Finally, we passed the items which is an array of BottomNavigationBarItem
.
And those are the two button you can see over here which is filled with the label text and an icon. We need to specify the pages to show based on the selected tabs. We would switch the current body of the Scaffold
widget when we select a different item.
But first, let’s extract the current body into a new page. This would be the HomePage
and it would live inside the pages folder.
I’ll do that now.
Next, we need to be able to change the body of the Scaffold
based on the selected tab. We would need a StatefulWidget
for this because we want this widget to be able to rebuild itself based on the updated state. Convert the MainPage
widget to a StatefulWidget
. Click on the class definition, then click on the bulb icon and select “Convert to Stateful Widget.” This creates two classes.
The first is the StatefulWidget
itself while the second is the State
of the widget. In Flutter, widgets are immutable so we delgate the management of a mutable state to a separate state object. Whenever a StatefulWidget
is mounted or inflated, Flutter calls the createState()
method which generates the State
object.
Next, update state class to the following:
...
// Members
final List<Widget> _pages = [
const HomePage(),
const InboxPage(),
];
int _selectedIndex = 0;
...
// Scaffold
body: IndexedStack(
index: _selectedIndex,
children: <Widget>[..._pages],
),
...
// BottomNavigationBar
currentIndex: _selectedIndex,
Save your work. We added the _pages
list to hold the pages that would be displayed based on the selected tab. Over here, we pass the HomePage
we just refactored and an Inbox
page that has been added to the starter project of this episode.
Next, we add the _selectedIndex
variable and set it to 0. Inside the Scaffold
’s body, we pass an IndexedStack
. This widget simply takes in a list of widgets and displays only one based on the selected index. Next, we use a spread operator to feed in the pages list to the children of the IndexedStack
.
It should display the first item in the _pages
list which is the home screen. Next, the currentIndex
property of the BottomNavigationBar
is set to the _selectedIndex
. This makes sure that when the selectedIndex
value is updated, the BottomNavigationBarItem
updates accordingly.
Let’s change to _selectedIndex
value to 1 and see the changes. Then do a hot restart to remount the widget. We need to do a hot restart because we just manually changed the value of a state member.
You can see it updates the selected item and the Scaffold
‘s body. Let’s quickly change that back to 0. Now, we don’t want to do this manually and that was why we changed this widget to a StatefulWidget
. Here, _selectedIndex
is a member of the state object and when this value is changed, Flutter would rebuild the UI to the updated appearance.
Let’s create the method that does this. Add the following code just before the build method:
_onTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
This method sets the value of _selectedIndex
to the index that is passed to it. The setState()
method is provided by the State
class. It notifies Flutter that the State object has changed which in turn, triggers a widget rebuild.
Next, set this as the onTap
property of the BottomNavigationBar
:
...
onTap: _onTapped,
...
Save your work. With this setup, the body is updated based on the selected tab.