Flutter UI Widgets

Nov 9 2021 Dart 2.14, Flutter 2.5, VS Code 1.61

Part 1: Flutter UI Widgets

6. Work with BottomNavigationBar

Episode complete

Play next episode

Next
About this episode
See versions

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 5. Create Scrollable Contents Next episode: 7. Use the FutureBuilder Widget

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.