Skip to main content

Flutter & Dart: Drawer Navigation

In this post we will learn how to navigate from one page to another using drawer menu options. As we all know that, app is just a widget in flutter, or a description of the UI portrayed. Each class which we create by extending StatelessWidget class gives us the ability to describe the part of our UI by building a constellation of other widget that describes our User Interface more loosely coupled.

So, the example which I will be implementing here is going to have one drawer to the top left of the screen on the app bar, which will have some menus. These menus will open UI respectively on user click. Below are the screen shots for the same:



Follow the below steps to implement this:
  • Run VSCode and press ctrl+shift+p and run Doctor Command to make sure everything is up and running. See if Doctor command runs without issue.
  • Press ctrl+shift+p and type 'New'. You will see the 'Flutter: New Project' command suggested in search, Like Below:



  • It will ask you to give the name for your project. Name it as "InkWell_drawer_Navigation".
  • Make sure you have your Emulator setup done. Start your emulator.
  • Now, we must make changes in our Main.Dart code file. Find this file in the project which we have just created.
  • At the end of this file create InkWellDrawer and CustomListTile class and add the following code:


  1. class InkWellDrawer extends StatelessWidget {  
  2.   @override  
  3.   Widget build (BuildContext ctxt) {  
  4.     return new Drawer(  
  5.         child: ListView(  
  6.           children: <Widget>[  
  7.             DrawerHeader(  
  8.               decoration: BoxDecoration(  
  9.                 gradient: LinearGradient(colors: <Color>[  
  10.                   Colors.lightBlue,  
  11.                   Colors.blue  
  12.                 ])  
  13.               ),  
  14.               child: Container(  
  15.                 child: Column(  
  16.                   children: <Widget>[  
  17.                     Material(  
  18.                       borderRadius: BorderRadius.all(Radius.circular(50.0)),  
  19.                       elevation: 10,  
  20.                       child: Padding(padding: EdgeInsets.all(8.0),  
  21.                       child: Image.asset("assets/images/drawerHeader.png", height: 90, width: 90),  
  22.                       ),  
  23.                     ),  
  24.                     Text('Flutter', style: TextStyle(color: Colors.white, fontSize: 25.0),)  
  25.                   ],  
  26.                 ),  
  27.               )),  
  28.             CustomListTile(Icons.person, 'Profile', ()=>{  
  29.               Navigator.pop(ctxt),  
  30.               Navigator.push(ctxt,   
  31.               new MaterialPageRoute(builder: (ctxt) => new HomeView())  
  32.               )  
  33.             }),  
  34.             CustomListTile(Icons.notifications, 'Notification', ()=>{  
  35.               Navigator.pop(ctxt),  
  36.               Navigator.push(ctxt,   
  37.               new MaterialPageRoute(builder: (ctxt) => new NotificationView())  
  38.               )  
  39.             }),  
  40.             CustomListTile(Icons.settings, 'Settings', ()=>{}),  
  41.             CustomListTile(Icons.lock'Log Out', ()=>{}),  
  42.           ],  
  43.   
  44.         ),  
  45.     );  
  46.   }  
  47. }  
  48.   
  49. class CustomListTile extends StatelessWidget{  
  50.   
  51.   final IconData icon;  
  52.   final  String text;  
  53.   final Function onTap;  
  54.   
  55.   CustomListTile(this.icon, this.text, this.onTap);  
  56.   @override  
  57.   Widget build(BuildContext context){  
  58.     //ToDO   
  59.     return Padding(  
  60.       padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 0),  
  61.       child:Container(  
  62.         decoration: BoxDecoration(  
  63.           border: Border(bottom: BorderSide(color: Colors.grey.shade400))  
  64.         ),  
  65.       child: InkWell(  
  66.         splashColor: Colors.orangeAccent,  
  67.         onTap: onTap,  
  68.         child: Container(  
  69.           height: 40,  
  70.           child: Row(  
  71.             mainAxisAlignment : MainAxisAlignment.spaceBetween,  
  72.             children: <Widget>[  
  73.             Row(children: <Widget>[  
  74.             Icon(icon),  
  75.             Padding(  
  76.               padding: const EdgeInsets.all(8.0),  
  77.             ),  
  78.             Text(text, style: TextStyle(  
  79.               fontSize: 16  
  80.             ),),  
  81.           ],),  
  82.         Icon(Icons.arrow_right)  
  83.       ],)  
  84.         )   
  85.     ),  
  86.     ),  
  87.     );  
  88.   }  
  89. }  

  • These above classes will add Drawer to our application. In this we are using InkWell class to make it look more attractive. So, if we look at our InkWellDrawer class then you will see that we have CustomListTile Class object which takes three parameters, first is Type of Icon. Second is Text for the menu and third is Action for event onTab. 
  • Inside this CustomListTile class we have implemented our menu. 
  • We have rectangular area which response to our touch on the UI element. So, Splash is the grayed animated background which gets enable when we touch our UI Element, specially it happens with buttons.
  • Now, we will add our two views: ProfileView and NotificationView. Add these views in our main.dart class:


  1. class NotificationView extends StatelessWidget {  
  2.   @override  
  3.   Widget build(BuildContext context) {  
  4.     return Scaffold(  
  5.       drawer: InkWellDrawer(),  
  6.       appBar: new AppBar(title: new Text("Notifications"),),  
  7.       body: ListView(  
  8.         children: <Widget>[  
  9.           Stack(  
  10.             children: <Widget>[  
  11.               Padding(  
  12.                 padding: const EdgeInsets.only(bottom: 30.0),  
  13.                 child: ClipPath(  
  14.                   clipper: ClippingClass(),  
  15.                   child: Container(  
  16.                     height: 130.0,  
  17.                     decoration: BoxDecoration(color: Colors.blue),  
  18.                   ),  
  19.                 ),  
  20.               ),  
  21.               Positioned.fill(  
  22.                 child: Align(  
  23.                   alignment: Alignment.bottomCenter,  
  24.                   child: Container(  
  25.                     height: 90.0,  
  26.                     width: 90.0,  
  27.                     decoration: BoxDecoration(  
  28.                       image: new DecorationImage(  
  29.                         image: new AssetImage("assets/images/Notification.jpg"),  
  30.                       ) ,  
  31.                       shape: BoxShape.circle,  
  32.                       border: Border.all(  
  33.                         color: Colors.white,  
  34.                         width: 5.0,  
  35.                       ),  
  36.                     ),  
  37.                   ),  
  38.                 ),  
  39.               )  
  40.             ],  
  41.           ),  
  42.           Container(  
  43.             padding: const EdgeInsets.only(top: 32.0),  
  44.             child: Column(  
  45.               children: <Widget>[  
  46.                 Text('Hello Bhupesh!!!'),  
  47.                 Padding(  
  48.                   padding:  
  49.                       const EdgeInsets.only(top: 22.0, left: 42.0, right: 42.0),  
  50.                   child: Center(child: Text('Welcome to your Notification View!!!')),  
  51.                 )  
  52.               ],  
  53.             ),  
  54.           ),  
  55.         ],  
  56.       ),  
  57.     );  
  58.   }  
  59. }  
  60. class ProfileView extends StatelessWidget {  
  61.   @override  
  62.   Widget build(BuildContext context) {  
  63.     return Scaffold(  
  64.       drawer: InkWellDrawer(),  
  65.       appBar: new AppBar(title: new Text("Profile"),),  
  66.       body: ListView(  
  67.         children: <Widget>[  
  68.           Stack(  
  69.             children: <Widget>[  
  70.               Padding(  
  71.                 padding: const EdgeInsets.only(bottom: 30.0),  
  72.                 child: ClipPath(  
  73.                   clipper: ClippingClass(),  
  74.                   child: Container(  
  75.                     height: 130.0,  
  76.                     decoration: BoxDecoration(color: Colors.blue),  
  77.                   ),  
  78.                 ),  
  79.               ),  
  80.               Positioned.fill(  
  81.                 child: Align(  
  82.                   alignment: Alignment.bottomCenter,  
  83.                   child: Container(  
  84.                     height: 90.0,  
  85.                     width: 90.0,  
  86.                     decoration: BoxDecoration(  
  87.                       image: new DecorationImage(  
  88.                         image: new AssetImage("assets/images/bhupesh.jpg"),  
  89.                       ) ,  
  90.                       shape: BoxShape.circle,  
  91.                       border: Border.all(  
  92.                         color: Colors.white,  
  93.                         width: 5.0,  
  94.                       ),  
  95.                     ),  
  96.                   ),  
  97.                 ),  
  98.               )  
  99.             ],  
  100.           ),  
  101.           Container(  
  102.             padding: const EdgeInsets.only(top: 32.0),  
  103.             child: Column(  
  104.               children: <Widget>[  
  105.                 Text('Hello Bhupesh!!!'),  
  106.                 Padding(  
  107.                   padding:  
  108.                       const EdgeInsets.only(top: 22.0, left: 42.0, right: 42.0),  
  109.                   child: Center(child: Text('Welcome to your Profile, Although, you do not have much to say in your profile apart from your cool image!!!')),  
  110.                 )  
  111.               ],  
  112.             ),  
  113.           ),  
  114.         ],  
  115.       ),  
  116.     );  
  117.   }  
  118. }  
  119. class ClippingClass extends CustomClipper<Path> {  
  120.   @override  
  121.   Path getClip(Size size) {  
  122.     var path = Path();  
  123.     path.lineTo(0.0, size.height - 80);  
  124.     path.quadraticBezierTo(  
  125.       size.width / 4,  
  126.       size.height,  
  127.       size.width / 2,  
  128.       size.height,  
  129.     );  
  130.     path.quadraticBezierTo(  
  131.       size.width - (size.width / 4),  
  132.       size.height,  
  133.       size.width,  
  134.       size.height - 80,  
  135.     );  
  136.     path.lineTo(size.width, 0.0);  
  137.     path.close();  
  138.     return path;  
  139.   }  
  140.   
  141.   @override  
  142.   bool shouldReclip(CustomClipper<Path> oldClipper) => false;  
  143. }  
  • NotificationView and ProfileView are the stateless classes which we have used to accomplish our views for profile and notification. We could have had more generic code because both classes are using the same theme for UI but for more clarity, I didn’t make it more generic so you could understand the code and implement the same and then make it more generic. 
  • Both classes are using the same Drawer which we have assigned using InkwellDrawer() fuction to drawer object. InkWell is our class which we have used earlier for implementing our drawer. It is good to have drawer object to be same drawer to make drawer available in all views. Otherwise, it wouldn’t be available to all views and we will find hard to navigate because we must go back to home page and then we needed to click on the menu in drawer.
  • For Clipper we have one more class for customizing our clipper which we are doing in ClippingClass.
  • Once you have implemented all these classes then go to the main build method and write the below code:


  1. @override  
  2.   Widget build(BuildContext context) {  
  3.     // This method is rerun every time setState is called, for instance as done  
  4.     // by the _incrementCounter method above.  
  5.     //  
  6.     // The Flutter framework has been optimized to make rerunning build methods  
  7.     // fast, so that you can just rebuild anything that needs updating rather  
  8.     // than having to individually change instances of widgets.  
  9.     return Scaffold(  
  10.       appBar: AppBar(  
  11.         // Here we take the value from the MyHomePage object that was created by  
  12.         // the App.build method, and use it to set our appbar title.  
  13.         title: Text(widget.title),  
  14.       ),  
  15.       drawer: InkWellDrawer(),  
  16.       body: Center(  
  17.         // Center is a layout widget. It takes a single child and positions it  
  18.         // in the middle of the parent.  
  19.         child: Column(  
  20.           // Column is also layout widget. It takes a list of children and  
  21.           // arranges them vertically. By default, it sizes itself to fit its  
  22.           // children horizontally, and tries to be as tall as its parent.  
  23.           //  
  24.           // Invoke "debug painting" (press "p" in the console, choose the  
  25.           // "Toggle Debug Paint" action from the Flutter Inspector in Android  
  26.           // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)  
  27.           // to see the wireframe for each widget.  
  28.           //  
  29.           // Column has various properties to control how it sizes itself and  
  30.           // how it positions its children. Here we use mainAxisAlignment to  
  31.           // center the children vertically; the main axis here is the vertical  
  32.           // axis because Columns are vertical (the cross axis would be  
  33.           // horizontal).  
  34.           mainAxisAlignment: MainAxisAlignment.center,  
  35.           children: <Widget>[  
  36.             Text(  
  37.               'You have pushed the button this many times:',  
  38.             ),  
  39.             Text(  
  40.               '$_counter',  
  41.               style: Theme.of(context).textTheme.display1,  
  42.             ),  
  43.           ],  
  44.         ),  
  45.       ),  
  46.       floatingActionButton: FloatingActionButton(  
  47.         onPressed: _incrementCounter,  
  48.         tooltip: 'Increment',  
  49.         child: Icon(Icons.add),  
  50.       ), // This trailing comma makes auto-formatting nicer for build methods.  
  51.     );  
  52.   }  
  53. }  

  • I didn't remove the counter logic code on home page which comes by default when we create flutter project. You can remove that to have nothing on your home page or you can keep that. You will notice that we have used our custom drawer for the drawer object. once you have done these changes, launch your emulator. Press ctrl+shift+p and type Flutter: Launch Emulator. Make sure you have one. Now press F5 to run the application. You should be able to see the drawer which we implemented, and you should be able to navigate to the profile and navigation views.



Congratulations!!!
Let me know for any issues.




Comments

Popular posts from this blog

Flutter & Dart VSCode: Creating Custom Material Drawer using InkWell for Android

In this exapmle, we will learn how to add customize material drawer with some cool UI look as well as some ripple effect just like below :   Couple of things we should have on our machine prior to implement this functionality: Enviornment setup on VS Code:  Follow my previous post Create New Project:  Follow my previous post Now, Follow the below steps: Once you have your project created, then you will notice in the project structure we have 'Main.Dart' file.Go to 'Main.Dart' file and add below class and name it  CustomListTile class  CustomListTile extends StatelessWidget{        final IconData icon;     final  String text;     final Function onTap;        CustomListTile( this .icon,  this .text,  this .onTap);     @ override     ...

Install Flutter & Dart on windows

Things we should have in order to work with Flutter and dart: Visual Studio Code Android Studio So first install these two guys from the link. Something About the Cross Platform Mobile Development: Cross Platform Mobile development refers to one common development platform which can be used for multiple mobile operating system like Android, iOS and Windows. There are number of technologies which support cross platform mobile development and to name a few are like Xamarin, CodeName One, Flutter & Dart, Apache Cordova  etc. I did one review about Xamarin technology because it's been while that I am using Xamarin for Android and iOS. You can read more about it,  Here... Flutter & Dart Flutter is Google’s portable UI toolkit for building beautiful, natively-compiled applications for mobile, web, and desktop from a single codebase. Dart is the language which we use for cross platform mobile development with Flutter.  In this example we ...