Flutter VI: Navigation Drawer

Chema Rubio
Flutter Community
Published in
5 min readJun 3, 2019

--

Material Design applications are used to handle navigation using tabs or drawers. Why drawers ? They are handy when lots of items need to be displayed.

Index

TIP: The whole Flutter series code is available in this repository.

Adding a Navigation Drawer

The main goal for this post is adding a Navigation Drawer to the application being developed along with these articles:

Drawer Widget

Our Navigation Drawer design may be divided into header, body and footer sections. The idea is having a reusable drawer with a couple of items within the drawer’s body that will trigger a navigation operation when tapped.

To do so, we’ll be using Drawer widget in combination with a Scaffold to create a layout with a Material Design Drawer.

AppDrawer

We’ll first focus on creating our Navigation Drawer.

Inside /lib/widgets folder, create a new file called drawer.dart. It will contain the drawer view logic.

So, if we analyze our design…

AppDrawer is a stateless widget, it’s child is a ListView in which children attribute we will nest the following elements:

  • _createHeader(): A function that returns a DrawerHeader widget.
  • _createDrawerItem(): This function will return a new DrawerItem each time it is called.
  • Divider(): We will use this widget between two DrawerItems whenever we want to separate items simulating sections.
  • ListTile(): Last but not least, this attribute represents the Drawer’s footer or its last element to be shown.

Let’s go coding! ᕕ( ᐛ )ᕗ

class AppDrawer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
_createHeader(),
_createDrawerItem(icon: Icons.contacts,text: 'Contacts',),
_createDrawerItem(icon: Icons.event, text: 'Events',),
_createDrawerItem(icon: Icons.note, text: 'Notes',),
Divider(),
_createDrawerItem(icon: Icons.collections_bookmark, text: 'Steps'),
_createDrawerItem(icon: Icons.face, text: 'Authors'),
_createDrawerItem(icon: Icons.account_box, text: 'Flutter Documentation'),
_createDrawerItem(icon: Icons.stars, text: 'Useful Links'),
Divider(),
_createDrawerItem(icon: Icons.bug_report, text: 'Report an issue'),
ListTile(
title: Text('0.0.1'),
onTap: () {},
),
],
),
);
}

Drawer Header

Taking our design into account, we wanted our header to have a background image and also a text to hold the application’s name.

To do so, our createHeader() function will return a Drawer header. The background image will be placed using a BoxDecoration holding an AssetImage we previously included in our assets. In order to create the text, we are using a Stack widget, just in case, we want our header to be modified in a short future. By now this stack will only have a text for children.

Widget _createHeader() {
return DrawerHeader(
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage('path/to/header_background.png'))),
child: Stack(children: <Widget>[
Positioned(
bottom: 12.0,
left: 16.0,
child: Text("Flutter Step-by-Step",
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w500))),
]));
}

Drawer Items

Each item is created the same way, allowing attributes such as an icon, text, and an onTap callback to be set. In the end, each item representation will be made from an icon and a text.

Widget _createDrawerItem(
{IconData icon, String text, GestureTapCallback onTap}) {
return ListTile(
title: Row(
children: <Widget>[
Icon(icon),
Padding(
padding: EdgeInsets.only(left: 8.0),
child: Text(text),
)
],
),
onTap: onTap,
);
}

Drawer Routes

Once our drawer is finished, we need some routes to be defined before we can perform any navigation.

Routes definition

Get back to lib/routes/Routes.dart and specify a couple of new routes, let’s say… Events and Notes.

class Routes {
static const String contacts = ContactsPage.routeName;
static const String events = EventsPage.routeName;
static const String notes = NotesPage.routeName;
}

Additional Pages

The routes we’ve just specified need to match pages, those pages will need to specify this drawer for their Scaffold. Remember to specify this drawer in contacts_page as well.

Nothing fancy for the content of this page, just a text showing which route was selected.

  • Events
class EventsPage extends StatelessWidget {
static const String routeName = '/events';

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Events"),
),
drawer: AppDrawer(),
body: Center(child: Text("Events")));
}
}
  • Notes
class NotesPage extends StatelessWidget {

static const String routeName = '/notes';

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Notes"),
),
drawer: AppDrawer(),
body: Center(
child: Text("Notes")
)
);
}
}

Navigation

Go back to our AppDrawer widget class, implement onTap method for a couple of widgets in order to add navigation operations for different routes.

To do so, use Navigator.pushReplacementNamed providing a context and the route you want to navigate to. This navigator operation will replace the current route of the navigator that most tightly encloses the given context by pushing the given route and then disposing of the previous route once the new route has finished animating in.

class AppDrawer extends StatelessWidget {

@override
Widget build(BuildContext context) {
return Drawer(
...
...
_createDrawerItem(
icon: Icons.contacts,
text: 'Contacts',
onTap: () =>
Navigator.pushReplacementNamed(context, Routes.contacts)),
_createDrawerItem(
icon: Icons.event,
text: 'Events',
onTap: () =>
Navigator.pushReplacementNamed(context, Routes.events)),
_createDrawerItem(
icon: Icons.note,
text: 'Notes',
onTap: () =>
Navigator.pushReplacementNamed(context, Routes.notes)),
Divider(),
...
...
);
}
}

Result

Run the application and see the results.

Application result running

Conclusion

We’ve just build a navigation drawer this fast !

It’s pretty amazing how much you get just by typing Drawer().

Next articles may bring new things we’ve been recently working on/with, stay tuned and don’t miss a thing!

This post is related to step5 inside the GitHub repository.

--

--