Create a simple Bottom Navigation Bar in Flutter

This is my tutorial on how to create a simple bottom navigation bar. It’s very simple if you choose not to reinvent the wheel. We will first create a bottom navigational bar and then add some content in it. What we will use is the bottom_navy_bar package. I am using version 6.0.0.

  1. Open Visual Code.
  2. Create an new Flutter application CTRL+SHIFT+P (and select Flutter: New Application Project and select somewhere you keep your projects, click Select, and then name your project, I’ll go with simplemenu.
  3. Run the application with flutter run to see everything is in order and working before doing any changes.
  4. Then add bottom_navy_bar to your dependencies to the pubspec.yaml file so it looks something like this:
name: simplemenu
description: A new Flutter project.

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  bottom_navy_bar: ^6.0.0
dev_dependencies:
  flutter_test:
    sdk: flutter

flutter:
  uses-material-design: true

5. Add some code. Through the help of pedromassango who is actually the author of the package, we can use his example to have a simple bottom navigation bar:

import 'package:bottom_navy_bar/bottom_navy_bar.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FileIdea Menu',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("FileIdea Menu")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            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),
      ),
      bottomNavigationBar: BottomNavyBar(
        selectedIndex: _currentIndex,
        showElevation: true,
        itemCornerRadius: 24,
        curve: Curves.easeIn,
        onItemSelected: (index) => setState(() => _currentIndex = index),
        items: <BottomNavyBarItem>[
          BottomNavyBarItem(
            icon: Icon(Icons.apps),
            title: Text('Home'),
            activeColor: Colors.red,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.people),
            title: Text('Users'),
            activeColor: Colors.purpleAccent,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.message),
            title: Text(
              'Messages',
            ),
            activeColor: Colors.pink,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.settings),
            title: Text('Settings'),
            activeColor: Colors.blue,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }
}

The important part here is obviously that we are adding items (BottomNavyBarItems) to bottomNavigationBar‘s items property. You can change icon, title, active color, textalign too to whatever you want. Then selectedIndex is keeping track on which item should be active which we change (_currentIndex) whenever the user clicks on a item through onItemSelected.

How it looks after we are done here:

simple Bottom Navigation Bar sample result

Okay now what? So you got your menu, but nothing special happens we click on one of the navigational bottom bar menu items. We can play around with the currentIndex which we set for each time a menu item is clicked. So you can work with this index like so:

import 'package:bottom_navy_bar/bottom_navy_bar.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FileIdea Menu',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _currentIndex = 0;
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("FileIdea Menu")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Showing page $_currentIndex'),
          ],
        ),
      ),
      bottomNavigationBar: BottomNavyBar(
        selectedIndex: _currentIndex,
        showElevation: true,
        itemCornerRadius: 24,
        curve: Curves.easeIn,
        onItemSelected: (index) => setState(() => _currentIndex = index),
        items: <BottomNavyBarItem>[
          BottomNavyBarItem(
            icon: Icon(Icons.apps),
            title: Text('Home'),
            activeColor: Colors.red,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.people),
            title: Text('Users'),
            activeColor: Colors.purpleAccent,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.message),
            title: Text(
              'Messages',
            ),
            activeColor: Colors.pink,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.settings),
            title: Text('Settings'),
            activeColor: Colors.blue,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }
}

Showing a single page from simple Bottom Navigation Bar

So now we get 0 if we see “Showing page 0”, “Showing page 1” if we go to the people icon and so forth. Not very interesting though isn’t it? So if we want to add some “real” content we could go down the route and start adding routes and then go switch between pages that way with the help of Navigator.pop(context), maybe create some kind of a callback method to keep track of what’s happening, but there is another option, PageController.

With PageController we can set a “scrollable list that works page by page from an explicit [List] of widgets”. We set the PageControl inside the PageView which we set inside our initial page. By using this we will have all content at one place (kind of) and therefore it might be the most simple solution to achieve our goal of having a simple bottom navigation bar with content on each page.

import 'package:bottom_navy_bar/bottom_navy_bar.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'FileIdea Menu',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late PageController _pageController;

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
  }

  @override
  void dispose() {
    _pageController.dispose();
    super.dispose();
  }

  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("FileIdea Menu")),
      body: SizedBox.expand(
        child: PageView(
          controller: _pageController,
          onPageChanged: (index) {
            setState(() => _currentIndex = index);
          },
          children: <Widget>[
            Container(
              color: Colors.blueGrey,
            ),
            Container(
              color: Colors.red,
            ),
            Container(
              color: Colors.green,
            ),
            Container(
              color: Colors.blue,
            ),
          ],
        ),
      ),
      bottomNavigationBar: BottomNavyBar(
        selectedIndex: _currentIndex,
        showElevation: true,
        itemCornerRadius: 24,
        curve: Curves.easeIn,
        onItemSelected: (index) => {
          setState(() => _currentIndex = index),
          _pageController.jumpToPage(index)
        },
        items: <BottomNavyBarItem>[
          BottomNavyBarItem(
            icon: Icon(Icons.apps),
            title: Text('Home'),
            activeColor: Colors.pink,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.people),
            title: Text('Users'),
            activeColor: Colors.purpleAccent,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.message),
            title: Text(
              'Messages',
            ),
            activeColor: Colors.pink,
            textAlign: TextAlign.center,
          ),
          BottomNavyBarItem(
            icon: Icon(Icons.settings),
            title: Text('Settings'),
            activeColor: Colors.blue,
            textAlign: TextAlign.center,
          ),
        ],
      ),
    );
  }
}

Pay attention to the marked rows. We are now utulizing the jumpToPage() method from the _pageController so we can browse between the pages from the PageView children.

As you can see the colours change when we browse each page.

Now we have the ability to use the index and go between Widgets inside the PageView children. We already added 4 Containers that has different colors. Let us add something, what about a gallery perhaps?

Add a gallery as content

Let us start by typing stl and create a new stateless widget called PeopleContent then go to your pubspec.yaml and add gallery_view to your dependencies.

name: simplemenu
description: A new Flutter project.

publish_to: 'none'
version: 1.0.0+1

environment:
  sdk: ">=2.12.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  bottom_navy_bar: ^6.0.0

  cupertino_icons: ^1.0.2
  gallery_view: ^0.0.4

dev_dependencies:
  flutter_test:
    sdk: flutter
  pedantic: ^1.10.0

flutter:

  uses-material-design: true

Then add a GalleryView so we can see images at the people page like this:

class PeopleContent extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: GalleryView(imageUrlList: [
        "https://images.unsplash.com/photo-1500100586562-f75ff6540087?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
        "https://images.unsplash.com/photo-1523719185231-aff40a400361?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=60",
      ]),
    );
  }
}

Then inside your _MyHomePageState under the people, replace Container with color to your new PeopleContent Widget. If you get null safety error, try running with no sound null safety.

flutter run --no-sound-null-safety

Now if we take a look we have some images showing in our people page when we click on the menu item.

Browsing the bottom nav app

I realized the images has nothing to do with people but you get the point. It is easy to have content and a bottom navigational menu this way!

0 0 votes
Article rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments