Flutter: Setting up a Navigation Drawer with Multiple Fragments (Widgets)

If you’ve ever worked on a native Android app, then you would’ve surely come across NavigationDrawer. For those of you who are not aware of it or are completely new to mobile app development world, here’s a description of NavigationDrawer from Android’s official site:

The navigation drawer is a UI panel that shows your app’s main navigation menu. It is hidden when not in use, but appears when the user swipes a finger from the left edge of the screen or, when at the top level of the app, the user touches the drawer icon in the app bar.
Navigation Drawer Demo Flutter App (Drawer Opened)

I’ve been using this UI component a lot in my native Android apps. I wanted to do it on Flutter but I couldn’t find any good post explaining how to set up a simple Navigation Drawer widget with multiple pages/widgets.

Since I’m used to the term fragment, lets call each section or the widget you want to show as a fragment. (Why not?)

For this tutorial, I’ll assume that you want to have one main Page (analogous to Activity in Android) and multiple sections (fragments) in that Page. If you wish, you can also implement a multi-page Navigation Drawer that will simply push in new page on clicking a drawer item. I won’t be explaining the multi-page pattern here because it is too unrealistic and can cause a lot of issues with user experience.

This is how our project structure will be after end of this tutorial.

NavigationDrawer app project structure. (showing only lib/ folder, rest of the structure remains the same)

Create a new Flutter app project and delete all boilerplate code in lib/main.dart.

We will leave main.dart without any new additions. HomePage will be our default page that will include a NavigationDrawer.

Now let’s design lib/pages/home_page.dart

Firstly, we create a class for each item in the drawer menu (the list of options you see when you open the drawer). It will include a title and an icon, which we will later use to present as a ListTile. We define HomePage to be a StatefulWidget since we want to the save the state of selected drawer item. The HomePage class itself won’t include any state, since we will be defining state variables in HomePageState class. But make sure you initialize the list of DrawerItems in HomePage.

To keep track of currently selected drawer item, we use a state variable called _selectedDrawerIndex.

And we have a function _onSelectItem(int index) that will be called when a drawer item is selected in drawer menu. It will simply change _selectedDrawerIndex and call setState to re-render the whole page. Drawer will be closed using Navigator.of(context).pop().

_getDrawerItemWidget(int pos) will simply return a new widget of any type based on the selected drawer item. This widget is used to replace the existing widget in body: of the Scaffold.

Inside the build() function, we create a ListTile widget for each of our drawer item and set selected: true if the currently selected item’s index matches it.

Finally, inside Scaffold, you can use the drawer property to define the layout of the drawer menu itself. I’ve used UserAccountsDrawerHeader to get the looks of Android’s navigation drawer header and then simply followed by a Column widget that hosts our newly created ListTitles. Notice how I’ve used widget.drawerItems[_selectedDrawerIndex].title to set the title in Scaffold, here widget refers HomePage which allows us to access HomePage’s properties. Now we can simply use _getDrawerItem() to get the current widget (one among FirstFragment, SecondFragment, ThirdFragment)

You can define the Fragment classes or widgets like:

That’s it, now you can run the app on your phone and you should have a working NavigationDrawer.

Full source code: https://github.com/flutter-tuts/drawer_demo

Conclusion

As per my experience, you need to write a bit of boilerplate code with Flutter to add a navigation drawer to your app. For native Android apps, Android Studio can automatically generate these codes and I hope the Flutter IDE plugins will come with this feature soon. If you have any suggestions or another way to implement this, please feel free to leave a comment.

Thank you.