Flutter is a mobile App SDK by Google which helps in creating modern mobile apps for iOS and Android using a single(almost) code base. It’s a new entrant in the cross platform mobile application development and unlike other frameworks like React Native, it doesn’t use JavaScript but DART as a Programming Language.
It’s highly recommended to read my first post “Flutter: From Zero To Comfortable” to get a good sense of how Flutter widgets work and what’s going on here in this post.
What is a Drawer?
A drawer is an invisible side screen which generally contain menu items and occupies around half of the screen when displayed. If you’ve ever used apps like Twitter and/or GMail, you already know what I’m talking about.
Creating Empty Drawer
Let’s first create an empty drawer. As with other flutter applications with material design, we’ll be creating a basicMaterialApp
, the home of which shall contain a Scaffold
with Drawer
Here is how the code for basic MaterialApp
shall look like
class MyApp extends StatelessWidget { @override Widget build (BuildContext ctxt) { return new MaterialApp( home: new DWidget() ); } }
The DWidget
here is the widget which will contain drawers. It should be noted that drawers
are part of Scaffold
along with appBar
and body
. Once we add drawer to the Scaffold, it generates a three line menu item on the top left corner of the application bar, which on clicking displays the drawer screen.
Here is how the basic code shall look like.
class DWidget extends StatelessWidget { @override Widget build (BuildContext ctxt) { return new Scaffold( drawer: new Drawer( child: new Text("\n\n\nDrawer Is Here"), ), appBar: new AppBar( title: new Text("Drawer Demo"), ), body: new Text("Drawer Body"), ); } }
This will create an app with a bare minimum drawer as displayed below.
As you might have noticed that drawer, takes child:
and not children:
, which means at any point of time we can have only one widget inside drawer.
To have more than one widget, we need to use widgets which are capable of holding multiple child widgets like Column
. Here is how the drawer code will look with Column
drawer: new Drawer( child: new Column( children: <Widget>[ new Text("\n\n\n\Drawer Is Here => 1"), new Text("Drawer Is Here => 2"), new Text("Drawer Is Here => 3"), ], ) ),
This will display three lines of text in the drawer.
Adding Drawer Header
Now we know what drawers are and how it can be created. However, if we go ahead and compare our drawers with GMail or Twitter Drawer, we’ll notice that the drawers always come with a header which takes approximately ~20% space atthe top.
In flutter, we can create a similar header using DrawerHeader
widget which takes a child
and allows us to decorate the header. In here, I’m using BoxDecoration
so that we can distinguish the complete boundary of the widget.
Here is how the code with DrawerHeader
shall look like
drawer: new Drawer( child:new DrawerHeader( child: new Text("DRAWER HEADER.."), decoration: new BoxDecoration( color: Colors.orange ), ) ),
And here is how the existing drawer changes
It must be surprising to see header taking the 100% of the drawer whereas it was suppose to take only around 20% of the space on top.
This happens because within the drawer
child
, we only haveDrawerHeader
and nothing else.
Moving Drawer Header to the Top
To move the drawer header on top of the drawer, we need to use the widgets which can contain multiple widgets (e.g. children:) like Column
on ListView
.
We’re going to use ListView
over here as the Column
doesn’t take all the available space evenly, which will leave patches of empty space onthe screen. Here is how we can use the ListView
inside the Drawer
drawer: new Drawer( child: new ListView( children: <Widget>[ new DrawerHeader( child: new Text("DRAWER HEADER.."), decoration: new BoxDecoration( color: Colors.orange ), ) ], ) ),
And here is how the resulting app shall look like
Now, this is what we were looking for. This also resembles the apps like GMail and Twitter drawer header.
Now, we can decorate the header the way we want and have as many items and links as possible.
I’ll come back to decorating headers in some later posts, in this post we’ll proceed ahead with finishing the functionality of drawer and add some actionable items
Adding Actionable Items in Drawer
Since we want some actions to be performed when someone selects(or taps) one the items of the drawer, we need to use widgets which can handle onTap
method, or alternatively we need to create a container around widgets to handle gestures.
However, using widgets with in-built
onTap
handler is preferred over here because of its ease of use.
One such widget which we can use inside the
ListView
isListTile
Let’s create couple of items using ListTile
and add corresponding actions using onTap()
method.
There are many actions we can add on onTap(), however, most often we’ll end up loading a new page with onTap()
Loading new Pages
I’ve explained how to load new pages in my another Flutter article called Flutter: Creating Multi Page Application with Navigation .
I’ll highly recommend reading this article to understand how navigation works in flutter. We’ll be using the same method over here to load a new Page onto the screen.
In here, we’ll create a couple of pages (i.e. widgets) and load them as a result of an action from end users on drawers
class FirstPage extends StatelessWidget { @override Widget build(BuildContext ctxt) { return new Scaffold( appBar: new AppBar(title: new Text("First Page"),), body: new Text("I belongs to First Page"), ); } } class SecondPage extends StatelessWidget { @override Widget build(BuildContext ctxt) { return new Scaffold( appBar: new AppBar(title: new Text("Second Page"),), body: new Text("I belongs to Second Page"), ); } }
Let’s load them as onTap()
action on ListTile
. Here is how the complete drawer code shall look like
drawer: new Drawer( child: new ListView( children: <Widget>[ new DrawerHeader( child: new Text("DRAWER HEADER.."), decoration: new BoxDecoration( color: Colors.orange ), ), new ListTile( title: new Text("Item => 1"), onTap: () { Navigator.push(ctxt, new MaterialPageRoute(builder: (ctxt) => new FirstPage())); }, ), new ListTile( title: new Text("Item => 2"), onTap: () { Navigator.push(ctxt, new MaterialPageRoute(builder: (ctxt) => new SecondPage())); }, ), ], ) ),
And here is how the actions will look like on the app
Making Drawer Disappear
We’ve successfully able to load the new pages on click of drawer items, however, when we try to come back on the original page, the drawer remains loaded there (as can be seen in the picture above).
This is annoying as we don’t want the drawers to remain there unless we explicitly load it again
This can be achieved by unloading the drawer before we load a new page by calling Navigator.pop()
. Here is how the onTap()
code shall be changed
onTap: () { Navigator.pop(ctxt); Navigator.push(ctxt, new MaterialPageRoute(builder: (ctxt) => new FirstPage())); },
And the resultant screen will not keep the drawers on the original Page
Making Drawer available across all Pages
We generally create common actions on drawers which which should be made available across the whole application. This can be done by making sure that the drawers are available to each Scaffold
or all the pages.
This effectively means that we can have drawer code in a separate stateless widget as
class DrawerOnly extends StatelessWidget { @override Widget build (BuildContext ctxt) { return new Drawer( child: new ListView( children: <Widget>[ new DrawerHeader( child: new Text("DRAWER HEADER.."), decoration: new BoxDecoration( color: Colors.orange ), ), new ListTile( title: new Text("Item => 1"), onTap: () { Navigator.pop(ctxt); Navigator.push(ctxt, new MaterialPageRoute(builder: (ctxt) => new FirstPage())); }, ), new ListTile( title: new Text("Item => 2"), onTap: () { Navigator.pop(ctxt); Navigator.push(ctxt, new MaterialPageRoute(builder: (ctxt) => new SecondPage())); }, ), ], ) ); } }
and use this inside our widgets with Scaffold
class DWidget extends StatelessWidget { @override Widget build (BuildContext ctxt) { return new Scaffold( drawer: new DrawerOnly(), // New Line appBar: new AppBar( title: new Text("Drawer Demo"), ), body: new Text("Drawer Body"), ); } } class FirstPage extends StatelessWidget { @override Widget build(BuildContext ctxt) { return new Scaffold( drawer: new DrawerOnly(), // new Line appBar: new AppBar(title: new Text("First Page"),), body: new Text("I belongs to First Page"), ); } } class SecondPage extends StatelessWidget { @override Widget build(BuildContext ctxt) { return new Scaffold( drawer: new DrawerOnly(), // New Line appBar: new AppBar(title: new Text("Second Page"),), body: new Text("I belongs to Second Page"), ); } }
And the resulting app will have drawers on all the pages
That’s all for this particular post. I hope I was able to explain how we can create and use drawers in flutter applications.
Thanks for reading….!!!
Daksh
Source: https://proandroiddev.com/flutter-creating-drawers-e31414f7d71a
Written by
Daksh
I do Code for living / This is my {Hub}
ProAndroidDev
Professional Android Development: the latest posts from Android Professionals and Google Developer Experts.