Sometimes, a Navigator isn’t the best choice for navigating between parts of your app. One significant consideration with it is that there is no user-facing interface to it, it’s entirely programmatic. Fortunately, Flutter offers a few visual navigation widgets too, one of which is the BottomNavigationBar. This widget provides a bar at the bottom of the screen with icons and/or text that the user can click to move between parts of your app.

In fact, this widget doesn’t really do any navigation itself, making its name a bit of a misnomer. The navigation part is up to your code, and really you don’t have to use it for navigation even! However, it normally is used to navigate, after a fashion, here’s one way to do so:

import "package:flutter/material.dart";
    void main() => runApp(MyApp());
    class MyApp extends StatefulWidget {
    MyApp({Key key}) : super(key : key);
    _MyApp createState() => _MyApp();
class _MyApp extends State {
    var _currentPage = 0;

    var _pages = [
        Text("Page 1 - Announcements"),
        Text("Page 2 - Birthdays"),
        Text("Page 3 - Data")

Widget build(BuildContext context) {
return MaterialApp(title : "Flutter Playground",
home : Scaffold(
body : Center(child : _pages.elementAt(_currentPage)),
bottomNavigationBar : BottomNavigationBar(
    items : [
            icon : Icon(Icons.announcement),
            title : Text("Announcements")
            icon : Icon(Icons.cake),
            title : Text("Birthdays")
        icon : Icon(,
        title : Text("Data")
    currentIndex : _currentPage,
    fixedColor :,
    onTap : (int inIndex) {
    setState(() { _currentPage = inIndex; });

Here, we start by creating a stateful widget. This is necessary because the top level widget is built once unless it has state that changes, which is precisely what we need to happen when the user clicks one of the items on the bar. Hence, we have to make this a stateful widget to provide that state. You’ll recall the pattern of needing to create two classes when dealing with state: a class extending from StatefulWidget and one extending from State. Although it may seem weird (it does to me anyway!), the class that actually is your widget is the one extending from State, not the one extending from StatefulWidget. Whether you find this weird or not, the key is to recognize the pattern. For the most part, the StatefulWidget class is basically boilerplate and will usually look about like what you see here, and the State class looks more or less like the StatelessWidget-extending widget classes you’ve seen a bunch of times now.

Getting into the actual State widget class, the state for this widget is the private _currentPage variable. The value of this is fed to the elementAt() method of the private _pages list. This determines what item from the list is the contents inside the Center widget (which could be an entire widget tree rather than a single Text widget). The bottomNavigationBar property of the Scaffold widget takes as its value an instance of BottomNavigationBar, which has an items property. This property is a list of BottomNavigationBarItem widgets. Each of those can have an icon and a title as we seem fit. Flutter comes with a collection of icons thanks to the Icons class, so we don’t even have to go digging around for graphics if we don’t want to! And, when working in Android Studio, you’ll have code completion, so you don’t even have to remember or even look up the icons when you need them! The currentIndex property of the BottomNavigationBar tells us which of the items on the bar is currently selected, and the fixedColor property determines what color to make that selected item.

Now, when the user taps one of the items, by default nothing will happen. To fix that, the onTap property is defined. This is a function that is passed the index of the tapped item. So, now we know what item from _pages we should display, but how does the value of _currentPage get updated? That’s where the call to the setState() method, supplied by virtue of this class extending the State class, comes into play. All we need to do is call this method and do the updates to the _currentPage variable in it. This triggers Flutter to rebuild the widget. Since _currentPage is different now, a different element from _pages will be displayed. The result for the user is that they appear to have navigated to a new page.