An Interesting Guide to Exploring Flutter Drawer

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

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

Drawer Header

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,
              ),
            ),
added drawer header

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");
              },
            ),
added user account drawer header

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:

yet to be filled

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

added drawer content

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

Drawer tutorial

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?

Leave a Comment