Flutter Navigation Drawer Tutorial and Example

This is a flutter navigation drawer tutorial with a full example. We start by discussing what navigation drawer is, when to use then look at a full example with fragments containing gridviews.

What is a Navigation Drawer?

A NavigationDrawer is a widget that allows us render navigation items in a sidebar with an optional user account profile. Navigation Drawer usually renders items in a ListView or ExpandableList. It usually has a header where we can display user account details like name, email, profile avatar et.

When a single navigation drawer item is clicked you navigate to a page or what we are calling fragments in this case.

When to use NavigationDrawer

Use navigation drawer when you have more items than can fit comfortably in a tabbar or bottomnavigation. Or if you find navigation drawer more intuitive to use of course.

Full Examples

1. Flutter Navigation Drawer – Fragments with GridViews

We will explore an example where we will render a navigation drawer with header containing user name, email as well as avatar. We will show a user image as avatar. We will also show a navigation drawer background image.

 

Flutter NavigationDrawer

Flutter NavigationDrawer

Then when the user clicks a single navigation drawer item we will open an associated fragment or page. That fragment will contain gridviews with some data.

We have three files:

  1. Fragments.dart – To define our Fragment classes. These are just stateless widgets.
  2. Home.dart – This is our home page. It’s also where we define our navigation drawer.
  3. main.dart – The classic main file with our main method. Entry point to our application.
(a). Fragments.dart
import 'package:flutter/material.dart';

  //Let's create a reusable method that can render GridView as long as it passed a
  //a BuildContext as well as list of strings
  Widget createGridView(BuildContext context,List<String> cosmicBodies) {

    //I will shuffle my data
    cosmicBodies.shuffle();

   // Then build my GridView and return it
    return new GridView.builder(
      itemCount: cosmicBodies.length,
      gridDelegate: new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2),
      itemBuilder: (BuildContext context, int index) {
        return new GestureDetector(
          child: new Card(
            elevation: 5.0,
            child: new Container(
              alignment: Alignment.centerLeft,
              margin: new EdgeInsets.only(top: 10.0, bottom: 10.0,left: 10.0),
              child: new Text(cosmicBodies[index]),
            ),
          ),
    );
    }
    );
  }
//Create Meteors Fragment. This will contains a gridview with our meteors
class Meteors extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var meteors = ["Tunguska","Crab Pulsar","Geminga","Calvera","Vela X-1","Gaspra",
    "Psyche","Pallas","Ceres","Pioneer","Haumea","Makemake","Eris"];

    return createGridView(context, meteors);
  }
}

//Create Moons Fragment. This will contains a gridview with our moons
class Moons extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var moons =  ["Phobos","Deimos","Moon","Triton","Proteus","Oberon","Umbriel","Ariel","Titan",
    "Rhea","Lapetus","Dione","Enceladus","Mimas","Ganymede","Callisto","IO","Europa"];

    return createGridView(context, moons);
  }
}

//Create Stars Fragment. This will contains a gridview with our stars
class Stars extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var stars = ["UY Scuti","VY Cani Majoris","VV Cephei","KY Cygni","Aldebaran","Canopus",
    "Sirius","Vega","Alpha Pegasi","Bellatrix","Pollux","Betelgeuse","Naos","Arcturus","Polaris",
      "Rigel","Deneb","Wezen","Antares","Eya Caninae"];

    return createGridView(context, stars);
  }
}

//Create Galaxies Fragment. This will contains a gridview with our galaxies
class Galaxies extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var galaxies = ["Messier 87","Andromeda","Sombrero","Whirlpool","Pinwheel","Milky Way",
    "Cartwheel", "Black Eye Galaxy","Star Bust","Centaurus","Triangulum","Sunflower",
    "Caldwell","Tadpole","Hoag's Object","Mallin 1","NGC 262","IC 1101"];

    return createGridView(context, galaxies);
  }
}
(b). Home.dart
import 'package:mr_nav_drawer/pages/Fragments.dart' as Fragments;
import 'package:flutter/material.dart';

//Let's define a DrawerItem data object
class DrawerItem {
  String title;
  IconData icon;
  DrawerItem(this.title, this.icon);
}
// Our Homepage
class HomePage extends StatefulWidget {
  //Let's define our drawer items, strings and images
  final drawerItems = [
    new DrawerItem("Meteors", Icons.strikethrough_s),
    new DrawerItem("Moons", Icons.place),
    new DrawerItem("Stars", Icons.stars),
    new DrawerItem("Galaxies", Icons.gavel)
  ];
  //Let's Create and Return state for this 'StatefulWidget'
  @override
  State<StatefulWidget> createState() {
    return new HomePageState();
  }
}
// Let's define state for our homepage. A state is just information for a widget.
class HomePageState extends State<HomePage> {
  int _selectedDrawerIndex = 0;

  //Let's use a switch statement to return the Fragment for a selected item
  _getDrawerFragment(int pos) {
    switch (pos) {
      case 0:
        return new Fragments.Meteors();
      case 1:
        return new Fragments.Moons();  
      case 2:
        return new Fragments.Stars();
      case 3:
        return new Fragments.Galaxies();

      default:
        return new Text("Error");
    }
  }
  //Let's update the selectedDrawerItemIndex the close the drawer
  _onSelectItem(int index) {
    setState(() => _selectedDrawerIndex = index);
    //we close the drawer
    Navigator.of(context).pop();
  }

  @override
  Widget build(BuildContext context) {
    List<Widget> drawerOptions = [];
    //Let's create drawer list items. Each will have an icon and text
    for (var i = 0; i < widget.drawerItems.length; i++) {
      var d = widget.drawerItems[i];
      drawerOptions.add(
        new ListTile(
          leading: new Icon(d.icon),
          title: new Text(d.title),
          selected: i == _selectedDrawerIndex,
          onTap: () => _onSelectItem(i),
        )
      );
    }
    //Let's scaffold our homepage
    return new Scaffold(
      appBar: new AppBar(
        // We will dynamically display title of selected page
        title: new Text(widget.drawerItems[_selectedDrawerIndex].title),
      ),
      // Let's register our Drawer to the Scaffold
      drawer: new Drawer(
        child: new Column(
          children: <Widget>[
            //Lets Create a material design drawer header with account name, email,avatar
            new UserAccountsDrawerHeader(
                accountName: new Text("Oclemy"),
                accountEmail: new Text("oclemmi@gmail.com"),
                currentAccountPicture: new CircleAvatar(backgroundImage:
                 new AssetImage("assets/profile.png"),),
            decoration: new BoxDecoration(
              image: new DecorationImage(
                image: new AssetImage("assets/bg.jpg"),
                fit: BoxFit.cover
              )
            ),
                ),
            new Column(children: drawerOptions)
          ],
        ),
      ),
      body: _getDrawerFragment(_selectedDrawerIndex),
    );
  }
}
(c). main.dart
import 'package:mr_nav_drawer/pages/Home.dart';
import 'package:flutter/material.dart';

//Lastly we come to our main app
class MyApp extends StatelessWidget {
  // This is the root of our application.
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Mr NavigationDrawer',
      theme: new ThemeData(
        primarySwatch: Colors.deepOrange,
      ),
      home: new HomePage(),
    );
  }
}

//Then we run our app
void main() => runApp(new MyApp());

Download the source code here.