In this post, we will learn how to navigate from one page to another using drawer menu options. As we all know, the 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 another 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 screenshots 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:
- class InkWellDrawer extends StatelessWidget {
- @override
- Widget build (BuildContext ctxt) {
- return new Drawer(
- child: ListView(
- children: <Widget>[
- DrawerHeader(
- decoration: BoxDecoration(
- gradient: LinearGradient(colors: <Color>[
- Colors.lightBlue,
- Colors.blue
- ])
- ),
- child: Container(
- child: Column(
- children: <Widget>[
- Material(
- borderRadius: BorderRadius.all(Radius.circular(50.0)),
- elevation: 10,
- child: Padding(padding: EdgeInsets.all(8.0),
- child: Image.asset("assets/images/drawerHeader.png", height: 90, width: 90),
- ),
- ),
- Text('Flutter', style: TextStyle(color: Colors.white, fontSize: 25.0),)
- ],
- ),
- )),
- CustomListTile(Icons.person, 'Profile', ()=>{
- Navigator.pop(ctxt),
- Navigator.push(ctxt,
- new MaterialPageRoute(builder: (ctxt) => new HomeView())
- )
- }),
- CustomListTile(Icons.notifications, 'Notification', ()=>{
- Navigator.pop(ctxt),
- Navigator.push(ctxt,
- new MaterialPageRoute(builder: (ctxt) => new NotificationView())
- )
- }),
- CustomListTile(Icons.settings, 'Settings', ()=>{}),
- CustomListTile(Icons.lock, 'Log Out', ()=>{}),
- ],
-
- ),
- );
- }
- }
-
- class CustomListTile extends StatelessWidget{
-
- final IconData icon;
- final String text;
- final Function onTap;
-
- CustomListTile(this.icon, this.text, this.onTap);
- @override
- Widget build(BuildContext context){
-
- return Padding(
- padding: const EdgeInsets.fromLTRB(8.0, 0, 8.0, 0),
- child:Container(
- decoration: BoxDecoration(
- border: Border(bottom: BorderSide(color: Colors.grey.shade400))
- ),
- child: InkWell(
- splashColor: Colors.orangeAccent,
- onTap: onTap,
- child: Container(
- height: 40,
- child: Row(
- mainAxisAlignment : MainAxisAlignment.spaceBetween,
- children: <Widget>[
- Row(children: <Widget>[
- Icon(icon),
- Padding(
- padding: const EdgeInsets.all(8.0),
- ),
- Text(text, style: TextStyle(
- fontSize: 16
- ),),
- ],),
- Icon(Icons.arrow_right)
- ],)
- )
- ),
- ),
- );
- }
- }
These above classes will add Drawer to our application. In this, we are using the 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 an event onTab.
Inside this CustomListTile class, we have implemented our menu.
We have a rectangular area which responds to our touch on the UI element. So, Splash is the grayed animated background which gets enable when we touch our UI Element, especially it happens with buttons.
Now, we will add our two views:
ProfileView and
NotificationView. Add these views in our
main.dart class,
- class NotificationView extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- drawer: InkWellDrawer(),
- appBar: new AppBar(title: new Text("Notifications"),),
- body: ListView(
- children: <Widget>[
- Stack(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.only(bottom: 30.0),
- child: ClipPath(
- clipper: ClippingClass(),
- child: Container(
- height: 130.0,
- decoration: BoxDecoration(color: Colors.blue),
- ),
- ),
- ),
- Positioned.fill(
- child: Align(
- alignment: Alignment.bottomCenter,
- child: Container(
- height: 90.0,
- width: 90.0,
- decoration: BoxDecoration(
- image: new DecorationImage(
- image: new AssetImage("assets/images/Notification.jpg"),
- ) ,
- shape: BoxShape.circle,
- border: Border.all(
- color: Colors.white,
- width: 5.0,
- ),
- ),
- ),
- ),
- )
- ],
- ),
- Container(
- padding: const EdgeInsets.only(top: 32.0),
- child: Column(
- children: <Widget>[
- Text('Hello Bhupesh!!!'),
- Padding(
- padding:
- const EdgeInsets.only(top: 22.0, left: 42.0, right: 42.0),
- child: Center(child: Text('Welcome to your Notification View!!!')),
- )
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
- class ProfileView extends StatelessWidget {
- @override
- Widget build(BuildContext context) {
- return Scaffold(
- drawer: InkWellDrawer(),
- appBar: new AppBar(title: new Text("Profile"),),
- body: ListView(
- children: <Widget>[
- Stack(
- children: <Widget>[
- Padding(
- padding: const EdgeInsets.only(bottom: 30.0),
- child: ClipPath(
- clipper: ClippingClass(),
- child: Container(
- height: 130.0,
- decoration: BoxDecoration(color: Colors.blue),
- ),
- ),
- ),
- Positioned.fill(
- child: Align(
- alignment: Alignment.bottomCenter,
- child: Container(
- height: 90.0,
- width: 90.0,
- decoration: BoxDecoration(
- image: new DecorationImage(
- image: new AssetImage("assets/images/bhupesh.jpg"),
- ) ,
- shape: BoxShape.circle,
- border: Border.all(
- color: Colors.white,
- width: 5.0,
- ),
- ),
- ),
- ),
- )
- ],
- ),
- Container(
- padding: const EdgeInsets.only(top: 32.0),
- child: Column(
- children: <Widget>[
- Text('Hello Bhupesh!!!'),
- Padding(
- padding:
- const EdgeInsets.only(top: 22.0, left: 42.0, right: 42.0),
- child: Center(child: Text('Welcome to your Profile, Although, you do not have much to say in your profile apart from your cool image!!!')),
- )
- ],
- ),
- ),
- ],
- ),
- );
- }
- }
- class ClippingClass extends CustomClipper<Path> {
- @override
- Path getClip(Size size) {
- var path = Path();
- path.lineTo(0.0, size.height - 80);
- path.quadraticBezierTo(
- size.width / 4,
- size.height,
- size.width / 2,
- size.height,
- );
- path.quadraticBezierTo(
- size.width - (size.width / 4),
- size.height,
- size.width,
- size.height - 80,
- );
- path.lineTo(size.width, 0.0);
- path.close();
- return path;
- }
-
- @override
- bool shouldReclip(CustomClipper<Path> oldClipper) => false;
- }
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() function 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 the 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 the home page and then we needed to click on the menu in the 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,
- @override
- Widget build(BuildContext context) {
-
-
-
-
-
-
- return Scaffold(
- appBar: AppBar(
-
-
- title: Text(widget.title),
- ),
- drawer: InkWellDrawer(),
- body: Center(
-
-
- child: Column(
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- mainAxisAlignment: MainAxisAlignment.center,
- children: <Widget>[
- Text(
- 'You have pushed the button this many times:',
- ),
- Text(
- '$_counter',
- style: Theme.of(context).textTheme.display1,
- ),
- ],
- ),
- ),
- floatingActionButton: FloatingActionButton(
- onPressed: _incrementCounter,
- tooltip: 'Increment',
- child: Icon(Icons.add),
- ),
- );
- }
- }
I didn't remove the counter logic code on the 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.