Newby Coder header banner

Navigation Drawer in a Flutter application

Flutter Navigation Drawer for Android/iOS app

A navigation drawer is a panel which can be pulled to display a menu typically containing the primary navigation options for an application

The drawer is hidden by default and appears when a user touches any visible drawer icon or through a gesture like swipe

Flutter provides Drawer component for implementing a navigation drawer

Navigation component is used to route to a screen

A route is a string mapped to a Widget object while a material app is initialized


Creating new Flutter App

Check Flutter installation to setup Flutter

Use flutter create command to create a Flutter project (here nc_navigation_drawer):

flutter create nc_navigation_drawer

App Code


main.dart declares a material app with routes which is a map of string to Widgets

nc_navigation_drawer/lib/main.dart
import 'package:flutter/material.dart';
import 'package:navigation_drawer_app/account.dart';
import 'package:navigation_drawer_app/home.dart';
import 'package:navigation_drawer_app/settings.dart';

void main() {
  runApp(MaterialApp(
    debugShowCheckedModeBanner: false,
    home: HomeScreen(), // route for home is '/' implicitly
    routes: <String, WidgetBuilder>{
      // declare routes
      SettingsScreen.routeName: (BuildContext context) => SettingsScreen(),
      AccountScreen.routeName: (BuildContext context) => AccountScreen(),
    },
  ));
}

These route names can then be navigated to using Navigator.of(context).pushNamed(routeName);


In drawer_state.dart, a state NavigationDrawerState is declared with getNavDrawer() function of type Drawer

This state is to be inherited by states of stateful Widgets for them to be able to access the drawer

getNavDrawer() returns the layout of Drawer, with navigation items which are routed based on their associated route name when clicked

nc_navigation_drawer/lib/drawer_state.dart
import 'package:flutter/material.dart';
import 'package:navigation_drawer_app/account.dart';
import 'package:navigation_drawer_app/settings.dart';


class NavigationDrawerState extends State<StatefulWidget> {

  Drawer getNavDrawer(BuildContext context) {
    var headerChild = DrawerHeader(child: Text("Navigation Drawer Header"));
    var aboutChild = AboutListTile(
        child: Text("About"),
        applicationName: "Navigation Drawer App",
        applicationVersion: "v1.0.0",
        applicationIcon: Icon(Icons.adb),
        icon: Icon(Icons.info));

    // ListTile denoting navigation item rendered for given icon and label
    ListTile getNavItem(var icon, String label, String routeName) {
      return ListTile(
        leading: Icon(icon),
        title: Text(label),
        // clicking the tile initiates navigation to routeName
        onTap: () {
          setState(() {
            // pop() closes the drawer
            Navigator.of(context).pop();
            // navigate to routeName
            Navigator.of(context).pushNamed(routeName);
          });
        },
      );
    }

    var navChildren = [
      headerChild,
      getNavItem(Icons.settings, "Settings", SettingsScreen.routeName),
      getNavItem(Icons.home, "Home", "/"),
      getNavItem(Icons.account_box, "Account", AccountScreen.routeName),
      aboutChild
    ];

    return Drawer(
      child: ListView(children: navChildren);,
    );
  }

  // kinda placeholder for build function, which gets overridden by a class inheriting this class
  @override
  Widget build(BuildContext context) {
    return Scaffold();
  }
}

Account screen whose state inherits from NavigationDrawerState and calls getNavDrawer() to set drawer for Scaffold that is rendered by it

nc_navigation_drawer/lib/account.dart
import 'package:flutter/material.dart';
import 'package:navigation_drawer_app/drawer_state.dart';

class AccountScreen extends StatefulWidget {
  static const String routeName = "/account";

  @override
  AccountScreenState createState() => AccountScreenState();
}

class AccountScreenState extends NavigationDrawerState {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Account"),
      ),
      body: Container(
          child: Center(
        child: Text("Account Screen"),
      )),
      // Set the nav drawer
      drawer: getNavDrawer(context),
    );
  }
}

Home screen, similar to account screen

nc_navigation_drawer/lib/home.dart
import 'package:flutter/material.dart';
import 'package:navigation_drawer_app/drawer_state.dart';

class HomeScreen extends StatefulWidget {
  @override
  HomeScreenState createState() => HomeScreenState();
}

class HomeScreenState extends NavigationDrawerState {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Navigation Drawer Example"),
      ),
      body: Container(
          child: Center(
        child: Text("Home Screen"),
      )),
      // Set the nav drawer
      drawer: getNavDrawer(context),
    );
  }
}

Settings screen declared as a StatelessWidget, and thus cannot access drawer but gets a Back button to go to previous screen

nc_navigation_drawer/lib/settings.dart
import 'package:flutter/material.dart';

class SettingsScreen extends StatelessWidget {
  static const String routeName = "/settings";

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Settings"),
      ),
      body: Container(
          child: Center(
        child: Text("Settings Screen"),
      )),
    );
  }
}

Run instructions

Ensure a supported device is connected or emulator/simulator is started

Go to project directory

Use flutter run command to run

flutter run

It builds and runs app on an available android/ios device


Screenshot/image

Android

cl-flutter-nagivation-drawer

iOS

cm_flutter_navigation_drawer_as1cm_flutter_navigation_drawer_as2cm_flutter_navigation_drawer_as3