Flutter has deeply focused on the key areas where a developer might face issues, such as introducing some pre-built widgets, unlike Android where we need to import dependencies for any third-party feature. Apart from that, Flutter has an excellent combination of animation and routing, respectively.
However, in this blog post, we have an interesting guide to exploring Flutter Drawer. Let’s begin.
Table of Contents
- Simple Drawer Widget
- Wrapping Up
Simple Drawer Widget
Under any dart file where a Scaffold Widget is returned, attach a Drawer() to Scaffold's drawer entity
.
return Scaffold(
appBar: AppBar(),
drawer: Drawer(),
);
On hot-reload, we shall see a three-horizontal-liner
icon appearing denoting that the Drawer has been implemented.
https://docs.flutter.dev/cookbook/design/drawer
A Drawer has these useful properties at the beginning:
- backgroundColor
- elevation
- shape
- child
Let’s proceed to the next one and understand an interesting aspect – The DrawerHeader
Widget.
Exploring DrawerHeader Widget
Under Drawer’s child
entity, add the following code snippet:
drawer: Drawer(
child: ListView(
children: [
DrawerHeader(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
curve: Curves.bounceOut,
decoration: BoxDecoration(color: Colors.grey[300]),
child: Column(
children: const [
CircleAvatar(
radius: 50,
),
SizedBox(
height: 8,
),
Text("User Title"),
],
),
),
],
),
),
UI View
This looks good but can be improved further (just a suggestion…).
For that, we need another exciting built-in Widget i.e.
Exploring UserAccountsDrawerHeader Widget
This Widget has all we need. It comes with two required parameters:
accountName
accountEmail
Note: We now do not need DrawerHeader anymore. This takes care of that as well.
Here’s the current code snippet:
UserAccountsDrawerHeader(accountName: Text("User Title", style: style,),
accountEmail: Text("dummyuseremail@somedomain.com", style: style,),
decoration: const BoxDecoration(
color: Colors.transparent,
),
arrowColor: Colors.transparent,
currentAccountPicture: const CircleAvatar(
radius: 40,
),
),
Let’s make this more interesting by adding multiple user-accounts-avatar. Upon modifying the above snippet:
UserAccountsDrawerHeader(accountName: Text("User Title", style: style,), accountEmail: Text("dummyuseremail@somedomain.com", style: style,),
decoration: const BoxDecoration(
color: Colors.blueAccent,
),
arrowColor: Colors.transparent,
currentAccountPicture: const CircleAvatar(
radius: 50,
backgroundColor: Colors.amber,
),
otherAccountsPictures: const [
CircleAvatar(radius: 40, backgroundColor: Colors.deepOrange),
CircleAvatar(radius: 40, backgroundColor: Colors.greenAccent),
CircleAvatar(radius: 40, backgroundColor: Colors.blueGrey),
],
onDetailsPressed: () {
debugPrint("Button event");
},
),
You surely must have seen this feature in a couple of apps as well.
In the above snippet, onDetailsPressed
will work when tapping usereEmail
.
Let’s proceed to the next one and style this Drawer().
Styling the Drawer
We shed some light on the Drawer’s properties under the heading Simple Drawer Widget. Let’s apply some creativity to the same.
We shall be doing the following stuff:
- Modifying the Drawer corners
- Changing the Background Color
- Apply Elevation
- Change Width
- Apply Semantic Label
Modifying the Drawer corners
With the use of a shape entity, we can achieve this task.
Code snippet
– Rounding all Corners
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(30)),
),
– Rounding specific Corners
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(30),
topRight: Radius.circular(30),
),
),
– Changing the Background Color
With the use of the backgroundColor entity, we can achieve this task.
backgroundColor: Colors.grey[300],
– Apply Elevation
elevation: 3,
– Change Width
Either provide a double value or make it dynamic using MediaQuery
.
width: MediaQuery.of(context).size.width * 0.75,
Cover 75% of the device’s screen width.
– Apply Semantic Label
A Semantic Label is nothing but a description of how the value is used.
semanticLabel: 'drawer_test',
So, by applying all of these inside the Drawer Widget, we shall get the following output:
Now, let’s fill up the remaining section of the Drawer in the upcoming heading.
Implementing Custom Contents Inside Drawer
For this part, we shall be creating a custom widget class having an icon and text followed by an arrow at the trailing side.
Create a new dart file drawer_custom_content_widget.dart
and add the following code snippet.
import 'package:flutter/material.dart';
class DrawerCustomContentWidget extends StatelessWidget {
const DrawerCustomContentWidget({
Key? key,
required this.title,
required this.icon,
}) : super(key: key);
final IconData icon;
final String title;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
child: Row(
children: [
Icon(
icon,
size: 36,
),
const SizedBox(
width: 15,
),
Text(
title,
textAlign: TextAlign.left,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
Icon(
Icons.arrow_right,
size: 30,
color: Colors.grey[400],
),
],
),
);
}
}
And, implementing this under ListView:
DrawerCustomContentWidget(title: 'My Profile', icon: Icons.person_rounded),
DrawerCustomContentWidget(title: 'Change Language', icon: Icons.language),
DrawerCustomContentWidget(title: 'Content 2', icon: Icons.abc_sharp),
DrawerCustomContentWidget(title: 'Content 3', icon: Icons.ac_unit),
DrawerCustomContentWidget(title: 'Content 4', icon: Icons.g_translate_sharp),
DrawerCustomContentWidget(title: 'Content 5', icon: Icons.gpp_maybe),
Here’s the modified UI View
Note: You might ask why you didn’t use Listitle Widget as it comes with pre-built required properties.
The short answer is that Listile creates a lot of overflow issues, especially if the content length goes high. Furthermore, it is also not a good practice to use this Widget.
———————–
We may count this blog post as the final stage of completion, but before that, there is one more important thing to do, i.e. Add a callback feature to make use of navigation.
Under drawer_custom_content_widget.dart
, do the following:
import 'package:flutter/material.dart';
class DrawerCustomContentWidget extends StatelessWidget {
const DrawerCustomContentWidget({
Key? key,
required this.title,
required this.icon,
this.onTap,
}) : super(key: key);
final IconData icon;
final String title;
final VoidCallback? onTap; //added as optional
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4),
child: Row(
children: [
Icon(
icon,
size: 36,
),
const SizedBox(
width: 15,
),
Text(
title,
textAlign: TextAlign.left,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
Icon(
Icons.arrow_right,
size: 30,
color: Colors.grey[400],
),
],
),
),
);
}
}
- Drawer side
DrawerCustomContentWidget(
title: 'My Profile',
icon: Icons.person_rounded,
onTap: () {
debugPrint("my profile tapped");
},
),
DrawerCustomContentWidget(
title: 'Change Language', icon: Icons.language),
- Full Source Code
class MyApp1 extends StatelessWidget {
MyApp1({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
TextStyle style = const TextStyle(color: Color(0xffffffff));
return Scaffold(
appBar: AppBar(),
drawer: Drawer(
backgroundColor: Colors.grey[200],
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: Radius.circular(30),
bottomRight: Radius.circular(30),
),
),
elevation: 3,
width: MediaQuery.of(context).size.width * 0.75,
semanticLabel: 'drawer_test',
child: ListView(
children: [
UserAccountsDrawerHeader(
accountName: Text(
"User Title",
style: style,
),
accountEmail: Text(
"dummyuseremail@somedomain.com",
style: style,
),
decoration: const BoxDecoration(
color: Colors.blueAccent,
),
arrowColor: Colors.transparent,
currentAccountPicture: const CircleAvatar(
radius: 50,
backgroundColor: Colors.amber,
),
otherAccountsPictures: const [
CircleAvatar(radius: 40, backgroundColor: Colors.deepOrange),
CircleAvatar(radius: 40, backgroundColor: Colors.greenAccent),
CircleAvatar(radius: 40, backgroundColor: Colors.blueGrey),
],
onDetailsPressed: () {
debugPrint("Button event");
},
),
const SizedBox(
height: 20,
),
DrawerCustomContentWidget(
title: 'My Profile',
icon: Icons.person_rounded,
onTap: () {
debugPrint("my profile tapped");
},
),
const DrawerCustomContentWidget(
title: 'Change Language', icon: Icons.language),
const DrawerCustomContentWidget(
title: 'Content 2', icon: Icons.abc_sharp),
const DrawerCustomContentWidget(
title: 'Content 3', icon: Icons.ac_unit),
const DrawerCustomContentWidget(
title: 'Content 4', icon: Icons.g_translate_sharp),
const DrawerCustomContentWidget(
title: 'Content 5', icon: Icons.gpp_maybe),
],
),
),
body: SafeArea(),
);
}
}
However, there is also a great tutorial available regarding Drawer Widget. Check it out
It’s time to wrap up this article. Hope you found it useful.
Wrapping Up
Thanks for your precious time.
So, in this blog post, we got to know an interesting guide to exploring Flutter Drawer and viewed some code snippets, examples, screenshots, internal links, etc.
If you think something is missing in this post or have any sort of queries, please share them with me in the comments section below. I would love to know that as well.
Link to GitHub Repositories, and YouTube Channel
Read out previous blogs – Click here
Also, read Keeping the Bottom Navigation Bar on every screen. How do we do that?