Hello, Welcome back. Glad that you’re here.
We're building a Movie App with the best coding practices and tools. In the previous tutorial, we created Movie Tabs.
In this tutorial, we'll create the navigation drawer on the home screen.
Drawer in Scaffold
Open home_screen.dart, and add the drawer:
Scaffold(
drawer: const NavigationDrawer(),
body: ///body
)
The drawer is a journey here, so create a new folder drawer in the presentation folder.
Create a new file navigation_drawer.dart:
//1
class NavigationDrawer extends StatelessWidget {
//2
const NavigationDrawer();
@override
Widget build(BuildContext context) {
//3
return Container(
width: Sizes.dimen_300.w,
color: Theme.of(context).primaryColor.withOpacity(0.7),
);
}
}
- A stateless widget
- Declare a
const
constructor so that we can useconst
on the home screen and improve little performance. - Return a
Container
with a fixed width of 300 and theprimaryColor
with 0.7 opacity.
Before running the app, don't forget to add an import statement in home_screen.dart. You can drag from the left side of the screen and see the navigation drawer. Ideally, we've to open the navigation drawer when we tap on the menu icon. As we've used a custom app bar, we'll have to open the navigation drawer explicitly.
Open movie_app_bar.dart, open the drawer on tap of menu icon:
GestureDetector(
onTap: () {
//1
Scaffold.of(context).openDrawer();
},
child: Align(
alignment: Alignment.topLeft,
child: SvgPicture.asset(
'assets/svgs/menu.svg',
height: Sizes.dimen_12.h,
),
),
)
- You'll get the access to the Scaffold above the tree by using
Scaffold.of(context)
, open the drawer by using the reference of the Scaffold.
Now run the app and click on the menu icon.
Blur Effect
In navigation_drawer.dart, add BoxDecoration and remove the
color
:
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Theme.of(context).primaryColor.withOpacity(0.7),
blurRadius: 4,
),
],
),
- Use
BoxDecoration
and addboxShadow
with blur radius as 4.
Run the app and see the effect. This gives a nice look to the drawer.
Logo
At top in the navigation drawer add the Logo
:
//1
SafeArea(
//2
child: Column(
//3
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//4
Padding(
padding: EdgeInsets.only(
top: Sizes.dimen_8.h,
bottom: Sizes.dimen_18.h,
left: Sizes.dimen_8.w,
right: Sizes.dimen_8.h,
),
//5
child: Logo(
height: Sizes.dimen_20.h,
),
),
],
),
),
- Use
SafeArea
to have logical space from the top. - For all the items in the vertical direction, use
Column
. - Use
CrossAxisAlignment.start
to have every item start from the left. - Add
Padding
from all directions to have proper space between the list items and the Logo. - Finally, use the
Logo
widget that we create and use inMovieAppBar
. If you remember, I intentionally added height as an argument for this Logo. Provide 20 height.
Run the application and see Logo.
Custom ListItem
NavigationListItem
In the drawer, we show Favorite Movies, Feedback, and About. So, we'll create a common component. Also, this is a journey, so create a new folder in the journey folder.
In journeys/drawer folder, create a new file navigation_list_item.dart:
This widget will show a title and when you tap on it, you'll navigate to a specific screen.
//1
class NavigationListItem extends StatelessWidget {
//2
final String title;
final Function onPressed;
const NavigationListItem({Key key, @requried this.title, @required this.onPressed})
: super(key: key);
@override
Widget build(BuildContext context) {
//3
return GestureDetector(
onTap: onPressed,
//4
child: Container(
//5
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Theme.of(context).primaryColor,
blurRadius: 2,
),
],
),
//6
child: ListTile(
title: Text(
title,
style: Theme.of(context).textTheme.subtitle1,
),
),
),
);
}
}
- Create a stateless widget.
- Add fields for title and a function
onPressed
, that will be called when you press the line item. - Use
GestureDetector
to have this title tappable. - We will use Container because we need to add a similar blurry effect to each line item.
- Add
BoxShadow
inBoxDecoration
withblurRadius
of 2 and primary color. - Use the
ListTile
from the flutter framework.
Comeback to navigation_drawer.dart, and add NavigationListItem
below the first child in the Column
.
//1
NavigationListItem(
title: 'Favorite Movies',
onPressed: () {},
),
//2
NavigationListItem(
title: 'Feedback',
onPressed: () {},
),
NavigationListItem(
title: 'About',
onPressed: () {},
),
- Use
NavigationListItem
for Favorite Movies and keep theonPressed
as an empty method right now. - Similarly add Feedback and About list item as well.
Now, run the application. You'll see three items below the logo.
NavigationExpandedListItem
I have decided to give language selection the drawer itself. So to show a dropdown on tap of the tile, we have to open a list of sub-items.
When you tap on the Language tile, you'll show English and Spanish as 2 options.
To make a tile to be expanded, we have ExpansionTile
that takes in a title and list of sub-list items.
In drawer folder, create another file navigation_expanded_list_item.dart.
class NavigationExpandedListItem extends StatelessWidget {
final String title;
//1
final List<String> children;
final Function onPressed;
const NavigationExpandedListItem({
Key key,
@required this.title,
@required this.children,
@required this.onPressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Theme.of(context).primaryColor,
blurRadius: 2,
),
],
),
//2
child: ExpansionTile(
title: Text(
title,
style: Theme.of(context).textTheme.subtitle1,
),
//3
children: <Widget>[
for (int i = 0; i < children.length; i++)
NavigationListItem(
title: children[i],
onPressed: () {},
),
],
),
);
}
}
- This is very similar to
NavigationListItem
, except that now it also has children as one of the required parameters. - Instead of
ListTile
, useExpansionTile
. children
passed in theNavigationExpandedListItem
is a list of strings and that used inExpansionTile
accepts List of Widgets. So, using thefor
loop iterate through the list of strings and create aNavigationListItem
.
Use this expanded list tile in the navigation_drawer.dart below the Favorite Movies line item.
NavigationExpandedListItem(
title: 'Language',
//1
children: [
'English',
'Spanish',
],
onPressed: (index) {},
),
- Add two languages as of now.
Now run the application and tap on the language line item. You'll see the dropdown of languages.
The sub-list in language should've little padding from the left as well because it should look like a nested item in language.
NavigationSubListItem
To do that let's create another line item.
In the navigation_list_item.dart file, create another stateless widget:
class NavigationSubListItem extends StatelessWidget {
final String title;
final Function onPressed;
const NavigationSubListItem({Key key, this.title, this.onPressed})
: super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Container(
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Theme.of(context).primaryColor,
blurRadius: 2,
),
],
),
child: ListTile(
//1
contentPadding: EdgeInsets.symmetric(horizontal: 32.w),
title: Text(
title,
style: Theme.of(context).textTheme.subtitle1,
),
),
),
);
}
}
- Exactly clone of this, just add
contentPadding
.
In NavigationExpandedListItem
, instead of NavigationListItem
use NavigationSubListItem
.
Run the application now and tap on the language list item now. Notice the color of the arrow that changes its direction on collapse and expanded state.
It doesn't match our app theme. So go in app.dart and add accentColor
in ThemeData
:
accentColor: AppColor.royalBlue,
Now run the app for the final time. This time, the color matches our theme.
By this, we've added NavigationDrawer.
This was all about creating NavigationDrawer with a blur effect. See you in the next part of the series.