Custom Drawer in Flutter

How to add a custom drawer to your mobile screen in Flutter.

Abdur Rehman
5 min readJan 14, 2023

While creating mobile applications, there are two primary options for navigation: Tabs and Drawers. When there is insufficient space to support tabs, drawers provide a handy alternative.

In this blog, I will create a simple application that will demonstrate how to implement a drawer widget and how to customize it according to your design.

Let’s dirty our hand with coding by practically implementing the drawer widget in flutter.

In Flutter, use the drawer widget in combination with a Scaffold to create a layout with Material Design drawer.

Code Example

Firstly, I will create a new project by name of “flutter_drawer”. And clear all the boilerplate comments and code to make it clear and easy to understandable. And create new class SimpleDrawerScreen in simple_drawer_screen.dart file and pass it to the Material() home property. It will look something like this.

void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});

// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SimpleDrawerScreen(),
);
}
}

Create a Scaffold

To add a drawer to the app, wrap it in a Scaffold widget. The scaffold supports special Material Design components, such as Drawers, AppBars and SnackBars.

return Scaffold(
appBar: AppBar(),
drawer: // Add a Drawer here in the next step.
);

Add a drawer

Now we will add the drawer widget to the Scaffold. You can pass any widget to the drawer, Like Container or SizedBox and customize it later, but it is often best to use the drawer widget from the library, which adheres to the Material Design spec.

return Scaffold(
drawer: Drawer(
child: // Populate the Drawer in the next step.
),
);

Add Items to the Drawer

Now we have a drawer in place, add content to it. We will add a ListView as a child to the Drawer. While you could use a Column widget. ListView is handy because it ensures the user can scroll through the options in the drawer if there isn’t enough vertical space to fit everything.

 

Drawer(
child: ListView(
// Remove any padding from the ListView.
padding: EdgeInsets.zero,
children: [
const DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text('Drawer Header'),
),
ListTile(
title: const Text('Item 1'),
onTap: () {
// Update the state of the app.
// ...
},
),
ListTile(
title: const Text('Item 2'),
onTap: () {
// Update the state of the app.
// ...
},
),
],
),
);

Output

When you run, the above code will create a simple and basic drawer like this.

The above code example will create this simple and basic drawer.
Simple Drawer, with no functionality

Customize Drawer

Now let’s add some functionality to the Drawer, like we said, Navigation to the new screen and customization of its UI.

Our final customize drawer will look something like this. I will also share its whole source code at the end of this article.

Customized drawer

Drawer Header

Now let’s create our own custom header of the drawer, where we show the user information and when click on it will redirect to the user profile screen.

/// Header of the Drawer
Material(
color: Colors.blueAccent,
child: InkWell(
onTap: (){
/// Close Navigation drawer before
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => UserProfile()),);
},
child: Container(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: 24
),
child: Column(
children: const[
CircleAvatar(
radius: 52,
backgroundImage: NetworkImage(
'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTB8fHNtaWx5JTIwZmFjZXxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=500&q=60'

),
),
SizedBox(height: 12,),
Text('Sophia',
style: TextStyle(
fontSize: 28,
color: Colors.white
),),
const Text('@sophia.com',
style: TextStyle(
fontSize: 14,
color: Colors.white
),),

],
),
),
),
),
Header of the Drawer

Drawer Menu List

In Drawer menu list is very important, where we show different options, like settings, profile etc. when clicking on these options it will redirect to the destined screen.

 /// Header Menu items
Column(
children: [
ListTile(
leading: Icon(Icons.home_outlined),
title: Text('Home'),
onTap: (){
/// Close Navigation drawer before
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen()),);
},
),
ListTile(
leading: Icon(Icons.favorite_border),
title: Text('Favourites'),
onTap: (){
/// Close Navigation drawer before
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => FavouriteScreen()),);
},
),
ListTile(
leading: Icon(Icons.workspaces),
title: Text('Workflow'),
onTap: (){},
),
ListTile(
leading: Icon(Icons.update),
title: Text('Updates'),
onTap: (){},
),
const Divider(color: Colors.black45,),
ListTile(
leading: Icon(Icons.account_tree_outlined),
title: Text('Plugins'),
onTap: (){},
),
ListTile(
leading: Icon(Icons.notifications_outlined),
title: Text('Notifications'),
onTap: (){},
),
],
)
Menu List of the Drawer

Full Code of Customized Drawer

class CustomizeDrawerScreen extends StatelessWidget {
const CustomizeDrawerScreen({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Customize Drawer'),
),
drawer: Drawer(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
/// Header of the Drawer
Material(
color: Colors.blueAccent,
child: InkWell(
onTap: (){
/// Close Navigation drawer before
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => UserProfile()),);
},
child: Container(
padding: EdgeInsets.only(
top: MediaQuery.of(context).padding.top,
bottom: 24
),
child: Column(
children: const[
CircleAvatar(
radius: 52,
backgroundImage: NetworkImage(
'https://images.unsplash.com/photo-1554151228-14d9def656e4?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTB8fHNtaWx5JTIwZmFjZXxlbnwwfHwwfHw%3D&auto=format&fit=crop&w=500&q=60'
// 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxzZWFyY2h8Mnx8c21pbHklMjBmYWNlfGVufDB8fDB8fA%3D%3D&auto=format&fit=crop&w=500&q=60'
),
),
SizedBox(height: 12,),
Text('Sophia',
style: TextStyle(
fontSize: 28,
color: Colors.white
),),
const Text('@sophia.com',
style: TextStyle(
fontSize: 14,
color: Colors.white
),),

],
),
),
),
),

/// Header Menu items
Column(
children: [
ListTile(
leading: Icon(Icons.home_outlined),
title: Text('Home'),
onTap: (){
/// Close Navigation drawer before
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => HomeScreen()),);
},
),
ListTile(
leading: Icon(Icons.favorite_border),
title: Text('Favourites'),
onTap: (){
/// Close Navigation drawer before
Navigator.pop(context);
Navigator.push(context, MaterialPageRoute(builder: (context) => FavouriteScreen()),);
},
),
ListTile(
leading: Icon(Icons.workspaces),
title: Text('Workflow'),
onTap: (){},
),
ListTile(
leading: Icon(Icons.update),
title: Text('Updates'),
onTap: (){},
),
const Divider(color: Colors.black45,),
ListTile(
leading: Icon(Icons.account_tree_outlined),
title: Text('Plugins'),
onTap: (){},
),
ListTile(
leading: Icon(Icons.notifications_outlined),
title: Text('Notifications'),
onTap: (){},
),
],
)
],
),
),
);
),
);
}
}

Note: I highly recommend giving a read to the flutter official documentation about the Drawer, it is very helpful. Doc

Source Code:

To access the full source code, this is my GitHub repo.

Your contribution

👏 Press the clap button below to show your support and motivate me to write better!
💬 Leave a response to this article by providing your insights, comments or wishes for the series.
📢 Share this article with your friends, colleagues on social media.
➕ Follow me on Medium.
⭐ Follow me on Github.

--

--

Abdur Rehman

Software Engineer || Flutter Developer || Blogger || Passionate storyteller || Bibliophile