1 00:00:00,000 --> 00:00:05,359 [MUSIC] 2 00:00:05,359 --> 00:00:07,850 Hi, my name's Jamie Huson. 3 00:00:07,850 --> 00:00:09,790 I'm an Android developer at Etsy. 4 00:00:09,790 --> 00:00:10,720 In this workshop, 5 00:00:10,720 --> 00:00:13,910 I'll walk you through implementing the navigation drawer pattern. 6 00:00:13,910 --> 00:00:17,810 Navigation drawer is a UI pattern to display top level navigation items 7 00:00:17,810 --> 00:00:22,590 on top of the main content of a screen, by having a sliding panel become visible. 8 00:00:22,590 --> 00:00:26,150 The drawer is triggered through tapping the Action Bar Drawer Indicator, or 9 00:00:26,150 --> 00:00:27,700 by sliding from the edge of the screen. 10 00:00:27,700 --> 00:00:32,360 There are two places to find information about its usage and implementation. 11 00:00:32,360 --> 00:00:36,060 Let's navigate to the Android Developer website, and open up Chrome. 12 00:00:37,580 --> 00:00:41,349 And go to d.android.com. 13 00:00:41,349 --> 00:00:42,650 Let's go to the Design section. 14 00:00:42,650 --> 00:00:46,580 On the left hand side, let's go to Patterns. 15 00:00:47,960 --> 00:00:50,650 And you can see Navigation Drawer listed here. 16 00:00:50,650 --> 00:00:53,130 Let's talk about some of the most important parts of this site. 17 00:00:53,130 --> 00:00:57,420 The Navigation Drawer won't solve the problem of an overly complex or 18 00:00:57,420 --> 00:01:00,580 confusing navigation hierarchy within an app. 19 00:01:00,580 --> 00:01:02,740 If you find yourself not having enough room for 20 00:01:02,740 --> 00:01:05,870 all your navigation elements, consider reorganizing your app 21 00:01:05,870 --> 00:01:10,200 to ensure navigation elements appear in logical places within the app. 22 00:01:10,200 --> 00:01:12,960 Here, you can see the site talks about how the navigation drawer 23 00:01:12,960 --> 00:01:14,810 is displayed to the user. 24 00:01:14,810 --> 00:01:18,280 Again, you can click and tap on the icon, or 25 00:01:18,280 --> 00:01:22,080 you can slide from the edge of the screen over to display the drawer. 26 00:01:22,080 --> 00:01:25,680 The drawer sits on top of the other main content of the screen. 27 00:01:26,680 --> 00:01:31,090 Next, Navigation Drawer should contain only top level navigation packets. 28 00:01:31,090 --> 00:01:34,750 That means you shouldn't navigate to items directly tied to a content on 29 00:01:34,750 --> 00:01:36,280 a specific screen. 30 00:01:36,280 --> 00:01:40,300 The user will be able to access the Navigation Drawer from almost any screen, 31 00:01:40,300 --> 00:01:43,822 either by tapping that icon, or by sliding out from the side, so 32 00:01:43,822 --> 00:01:47,130 that I can switch to a section in your app at any time. 33 00:01:48,530 --> 00:01:51,090 Next, the relationship between the Navigation Drawer and 34 00:01:51,090 --> 00:01:53,450 the Action Bar is important to consider. 35 00:01:53,450 --> 00:01:57,600 When the drawer is open, action items in the Action Bar shouldn't be visible. 36 00:01:57,600 --> 00:01:58,390 In most cases, 37 00:01:58,390 --> 00:02:02,480 there won't be any visible actions in the action bar while the drawer is open. 38 00:02:02,480 --> 00:02:05,940 In addition, any contextual action bar modes that are enabled 39 00:02:05,940 --> 00:02:07,440 should be hidden while the drawer is open. 40 00:02:08,550 --> 00:02:10,860 Finally, consider the back button behavior, and 41 00:02:10,860 --> 00:02:14,280 ensure you're following the guidelines laid out on this page correctly. 42 00:02:14,280 --> 00:02:17,410 Inconsistently implementing back navigation with the drawer 43 00:02:17,410 --> 00:02:19,610 can be confusing to users. 44 00:02:19,610 --> 00:02:23,060 For the most relevant information about implementing the Navigation Drawer, 45 00:02:23,060 --> 00:02:26,720 let's talk about visiting the Material Design Guidelines. 46 00:02:26,720 --> 00:02:30,760 To go there, we just go to google.com/design. 47 00:02:30,760 --> 00:02:34,750 Material Design was introduced with Lollipop version 21, but 48 00:02:34,750 --> 00:02:39,640 they provided the AppCompat library, and some other tools and views 49 00:02:39,640 --> 00:02:44,290 in the Android Support Library, to enable utilizing this on older platforms as well. 50 00:02:44,290 --> 00:02:47,490 Go ahead and go to Material Guidelines. 51 00:02:47,490 --> 00:02:51,670 And up here in the navigation drawer, under Patterns, 52 00:02:51,670 --> 00:02:54,010 we can see there's Navigation Drawer. 53 00:02:54,010 --> 00:02:58,155 So here we can find specific implementation details like spacing, 54 00:02:58,155 --> 00:02:59,230 padding, and 55 00:02:59,230 --> 00:03:03,320 the visual style that we should apply to our navigation drawer in our app. 56 00:03:03,320 --> 00:03:06,720 This is really useful, and we should make sure to write these things down or 57 00:03:06,720 --> 00:03:07,930 revisit this page often, 58 00:03:07,930 --> 00:03:11,210 when we're going through implementations of our navigation drawer in our code. 59 00:03:11,210 --> 00:03:14,065 With the information from both these sites understood, 60 00:03:14,065 --> 00:03:16,440 let's move on to creating a navigation drawer. 61 00:03:17,640 --> 00:03:19,580 To implement a navigation drawer, 62 00:03:19,580 --> 00:03:23,370 we can use the included activity template in Android Studio. 63 00:03:23,370 --> 00:03:24,930 To do that, let's create a new project. 64 00:03:26,420 --> 00:03:28,479 I'm gonna call my project Navigation Drawer. 65 00:03:32,938 --> 00:03:37,190 Next, just use the defaults here for API version. 66 00:03:37,190 --> 00:03:40,380 Now, in this screen for the activity template, let's go ahead and 67 00:03:40,380 --> 00:03:43,090 select Navigation Drawer Activity. 68 00:03:43,090 --> 00:03:44,670 You can call it whatever you want. 69 00:03:44,670 --> 00:03:46,210 It's going to create a fragment for us. 70 00:03:46,210 --> 00:03:47,820 You can call that whatever you want as well. 71 00:03:47,820 --> 00:03:49,350 I'm just gonna leave in all the defaults. 72 00:03:50,530 --> 00:03:52,490 Okay, our project's been created for us. 73 00:03:52,490 --> 00:03:56,640 You can see that it's dropped in quite a bit of code here and 74 00:03:56,640 --> 00:03:58,350 layouts, and some other things. 75 00:03:58,350 --> 00:04:00,970 Let's go ahead and talk through each part of this. 76 00:04:00,970 --> 00:04:04,010 First, let's look at our main activity layout. 77 00:04:04,010 --> 00:04:07,130 Here, you can see that the navigation drawer is included. 78 00:04:07,130 --> 00:04:11,980 Navigation Drawer Layout is part of the Android Support Library. 79 00:04:11,980 --> 00:04:16,540 This is just a layout, like relative layout or linear layout, but 80 00:04:16,540 --> 00:04:20,840 it has a few special properties that make it implement the drawer properties, 81 00:04:20,840 --> 00:04:22,810 such as sliding from the edge of the screen, and 82 00:04:22,810 --> 00:04:25,080 displaying content on top of other content. 83 00:04:26,090 --> 00:04:29,410 The main content of the screen is gonna go as a child 84 00:04:29,410 --> 00:04:31,880 of our Navigation Drawer layout. 85 00:04:31,880 --> 00:04:34,660 It's going to have full width and full height, so 86 00:04:34,660 --> 00:04:36,210 we're just gonna give it match parent. 87 00:04:36,210 --> 00:04:38,650 Match parent, that's what's been provided in this template. 88 00:04:38,650 --> 00:04:42,210 And then we could see that as commented throughout this code, 89 00:04:42,210 --> 00:04:47,260 to implement the actual drawer, we're going to use the layout_gravity attribute. 90 00:04:47,260 --> 00:04:49,100 They use the start value. 91 00:04:49,100 --> 00:04:53,780 You can also use left or right to support API versions older than API 17. 92 00:04:53,780 --> 00:05:00,740 So any content with a layout_gravity of left, right, start, or end, 93 00:05:00,740 --> 00:05:05,530 is going to have that drawer be drawn off the screen, and become visible when 94 00:05:05,530 --> 00:05:10,380 the user swipes in from either left-hand or right-hand side of the screen. 95 00:05:10,380 --> 00:05:16,130 Here we can see that the template creates a left-hand side drawer as a fragment. 96 00:05:16,130 --> 00:05:18,080 Now, you don't have to use a fragment. 97 00:05:18,080 --> 00:05:19,820 You can put in a static layout here. 98 00:05:19,820 --> 00:05:21,040 You can put in a container and 99 00:05:21,040 --> 00:05:24,670 put a fragment in later at run time using Java code. 100 00:05:24,670 --> 00:05:28,300 It's up to you, what you want to have in your navigation drawer. 101 00:05:28,300 --> 00:05:30,360 But in this case, they use a fragment. 102 00:05:30,360 --> 00:05:33,140 So we'll walk through how that was implemented. 103 00:05:33,140 --> 00:05:36,440 Next, let's look at the fragment navigation drawer layout. 104 00:05:36,440 --> 00:05:39,529 And we can see that it simply consists of list view. 105 00:05:39,529 --> 00:05:45,230 So, list view has elements that are bind at run time, using an adapter. 106 00:05:45,230 --> 00:05:48,080 So we're gonna have to look at the code for an adapter later, 107 00:05:48,080 --> 00:05:52,510 and see how this list of items gets created in our navigation drawer. 108 00:05:52,510 --> 00:05:55,300 We can see there's also a fragment main layout. 109 00:05:55,300 --> 00:05:58,680 This is the main content that shows in the screen. 110 00:05:58,680 --> 00:06:01,770 And this is the content that the navigation drawer goes on top of, 111 00:06:01,770 --> 00:06:03,090 when it's slid into view. 112 00:06:03,090 --> 00:06:07,570 You can see it simply consists of a text view, and it's called section_label. 113 00:06:07,570 --> 00:06:10,880 That's the ID, but it doesn't actually have any text in it. 114 00:06:10,880 --> 00:06:12,820 Now let's go ahead and look at the code. 115 00:06:12,820 --> 00:06:15,600 Let's open up the MainActivity first. 116 00:06:15,600 --> 00:06:18,830 You see that MainActivity extends ActionBarActivity. 117 00:06:18,830 --> 00:06:21,100 That's part of the AppCompat library. 118 00:06:21,100 --> 00:06:23,750 And it also implements this navigation drawer fragment, 119 00:06:23,750 --> 00:06:25,720 NavigationDrawerCallbacks. 120 00:06:25,720 --> 00:06:28,090 That's defined in the navigation drawer fragment, and 121 00:06:28,090 --> 00:06:29,080 we'll take a look at that in a minute. 122 00:06:30,900 --> 00:06:34,250 Scrolling down, we can see onCreate view sets the content view, 123 00:06:34,250 --> 00:06:37,510 it creates a fragment and sets it up. 124 00:06:37,510 --> 00:06:42,170 And finally, it implements that callback, onNavigationDrawerItemsSelected. 125 00:06:42,170 --> 00:06:47,340 And when an item is selected, it loads a new fragment into the main container. 126 00:06:47,340 --> 00:06:50,786 Remember, this container is the main content area of our activity. 127 00:06:50,786 --> 00:06:52,420 If we keep scrolling down, 128 00:06:52,420 --> 00:06:56,400 we can see that there is some additional code needed to restore the action bar. 129 00:06:56,400 --> 00:07:01,060 Remember that when the drawer slides open, the action bar items need to be hidden, 130 00:07:01,060 --> 00:07:04,140 if they're not relevant to the navigation drawer. 131 00:07:04,140 --> 00:07:09,549 And finally, we've overridden the onCreate options menu, onOptions items selected. 132 00:07:09,549 --> 00:07:13,940 These are the legacy options menu that correspond to the action bar. 133 00:07:13,940 --> 00:07:18,842 So again, when the Navigation Drawer is opened or closed, we're restoring items, 134 00:07:18,842 --> 00:07:20,828 or hiding items to the action bar. 135 00:07:24,469 --> 00:07:26,960 Next, let's go ahead and look at the NavigationDrawerFragment. 136 00:07:28,070 --> 00:07:32,000 You can see right away that it stores a state variable, 137 00:07:32,000 --> 00:07:36,045 so this is going to be storing in our on save instant state, 138 00:07:36,045 --> 00:07:38,685 which item is selected in the list of items. 139 00:07:38,685 --> 00:07:40,625 Remember that the fragment for 140 00:07:40,625 --> 00:07:44,635 the Navigation Drawer contains simply a list view, and it's bound by an adapter. 141 00:07:44,635 --> 00:07:47,145 So we're gonna be looking at that in just a minute. 142 00:07:47,145 --> 00:07:50,345 You can see that this fragment has a Navigation Drawer callback, 143 00:07:51,360 --> 00:07:54,950 has the empty constructor, which all fragments should have. 144 00:07:54,950 --> 00:07:57,600 And they're saving which item is selected in the drawer, 145 00:07:57,600 --> 00:07:59,110 into a shared preference object. 146 00:08:00,590 --> 00:08:02,530 You can see that they're restoring the state here, 147 00:08:02,530 --> 00:08:06,910 by pulling the selected position out of the savedInstanceState bundle, and 148 00:08:06,910 --> 00:08:10,872 then setting the item that it was the current selected position. 149 00:08:10,872 --> 00:08:14,470 And onCreateView, they're simply getting references to that list view, and 150 00:08:14,470 --> 00:08:15,640 then they're setting this adapter. 151 00:08:15,640 --> 00:08:17,600 This is a simple array adapter. 152 00:08:17,600 --> 00:08:21,340 It has just a few items, Section 1, Section 2, Section 3, that's just some 153 00:08:21,340 --> 00:08:25,530 text, so when we run this app, we should see those three different sections. 154 00:08:25,530 --> 00:08:28,940 And it has this Public method isDrawerOpen. 155 00:08:28,940 --> 00:08:32,990 This will allow the activity when it's drawing and selecting the action bar 156 00:08:32,990 --> 00:08:38,200 items through the menu callbacks to know whether the drawer is open or not. 157 00:08:38,200 --> 00:08:41,730 Setup is called just when the fragment is first created, 158 00:08:41,730 --> 00:08:45,460 and what this does it gives it a reference to the views it needs. 159 00:08:45,460 --> 00:08:47,170 That's the drawer layout, itself. 160 00:08:47,170 --> 00:08:51,170 You can see that there's the ability to set a custom drawer shadow using 161 00:08:51,170 --> 00:08:52,230 a drawable. 162 00:08:52,230 --> 00:08:57,690 And finally, it sets up the action bar to display the up indicator. 163 00:08:57,690 --> 00:09:00,740 Now, if you're using toolbar, you can also do that. 164 00:09:00,740 --> 00:09:06,752 Toolbar is introduced in the Android support library, when API21 was released. 165 00:09:06,752 --> 00:09:10,620 And Toolbar works just as well as Action Bar, in fact better sometimes, and 166 00:09:10,620 --> 00:09:13,910 that works with drawer layout in a very similar way. 167 00:09:13,910 --> 00:09:18,440 If you're using Action Bar though, you need to use this Action Bar drawer toggle. 168 00:09:18,440 --> 00:09:23,160 This is what actually changes the icon to show as the drawer 169 00:09:23,160 --> 00:09:25,070 icon versus the up carrot. 170 00:09:26,320 --> 00:09:30,710 What this drawer toggle is implementing are the navigation drawer call backs 171 00:09:30,710 --> 00:09:33,650 of when the drawer is open and when it's closed. 172 00:09:33,650 --> 00:09:37,448 So, this is really important because when it's open, we need to make sure we call 173 00:09:37,448 --> 00:09:41,660 back to the activity and it's calling here, supportInvalidateOptions menu. 174 00:09:41,660 --> 00:09:45,730 This ensures that the action bar items are going to be then hidden, 175 00:09:45,730 --> 00:09:48,410 once the drawer is opened or closed. 176 00:09:48,410 --> 00:09:50,860 You can see it's also being called an onDrawerOpened. 177 00:09:52,250 --> 00:09:57,040 One important part of the user experience of the drawer is making sure that when 178 00:09:57,040 --> 00:10:00,440 the app is first loaded, the user knows the drawer exists. 179 00:10:00,440 --> 00:10:04,315 To do that, they store a variable in a shared preference about whether the drawer 180 00:10:04,315 --> 00:10:06,905 has been opened once or not. 181 00:10:06,905 --> 00:10:09,245 So if the user comes to this app, opens it for 182 00:10:09,245 --> 00:10:11,395 the first time, they don't know about the drawer. 183 00:10:11,395 --> 00:10:13,915 The drawer is going to be opened automatically for them. 184 00:10:13,915 --> 00:10:19,380 Once it's been closed, they set this value called mUserLearnedDrawer to be true. 185 00:10:19,380 --> 00:10:20,720 They store that in the shared preference. 186 00:10:20,720 --> 00:10:23,990 That way when the user comes back to the app, the drawer won't always be open, 187 00:10:23,990 --> 00:10:26,720 it will simply be in the last state it was in. 188 00:10:26,720 --> 00:10:27,480 Finally, at the end, 189 00:10:27,480 --> 00:10:32,490 we can see the interface that is defined, called NavigationDrawerCallbacks. 190 00:10:32,490 --> 00:10:36,420 And this is what the activity was implementing so that the activity knows 191 00:10:36,420 --> 00:10:41,170 when an item in the navigation drawer is selected and what position is selected. 192 00:10:41,170 --> 00:10:44,220 So, onNavigationDrawerItemSelected gets called. 193 00:10:44,220 --> 00:10:47,550 And we can see, back in the main activity, when this happens, 194 00:10:47,550 --> 00:10:52,820 when a specific number is selected, again, it just loads a different fragment. 195 00:10:52,820 --> 00:10:56,870 So, for an app that you're designing or I'm building, 196 00:10:56,870 --> 00:11:01,360 instead of just loading any old fragment, you might be loading specific fragments. 197 00:11:01,360 --> 00:11:04,440 This is my list, my main activity feed. 198 00:11:04,440 --> 00:11:06,660 This is my profile fragment. 199 00:11:06,660 --> 00:11:09,810 We're going to be showing specific content based on 200 00:11:09,810 --> 00:11:11,830 top level navigation items in the drawer. 201 00:11:11,830 --> 00:11:13,567 Let's go ahead and run this app, and 202 00:11:13,567 --> 00:11:16,269 we'll see how the navigation drawer looks in practice. 203 00:11:21,689 --> 00:11:25,250 Here we can see the navigation drawer starts out open, which is expected. 204 00:11:25,250 --> 00:11:29,480 The first time it runs, it should show the user the navigation drawer exists. 205 00:11:29,480 --> 00:11:31,920 By default, the first item is selected in the list. 206 00:11:31,920 --> 00:11:35,080 The user can select any other item they want. 207 00:11:35,080 --> 00:11:37,770 And you can see that when it loads the other fragmented changes, 208 00:11:37,770 --> 00:11:41,110 it changes the title to be that fragment's title: Section 1. 209 00:11:41,110 --> 00:11:44,340 Or if we open it again, we can do Section 3. 210 00:11:44,340 --> 00:11:46,960 And you can see that there's an example action up here. 211 00:11:46,960 --> 00:11:49,220 And when we open the drawer, those are hidden. 212 00:11:49,220 --> 00:11:50,460 The title changes. 213 00:11:50,460 --> 00:11:53,860 These were following the guidelines laid out in the developer website, 214 00:11:53,860 --> 00:11:55,490 Material Design Guidelines. 215 00:11:55,490 --> 00:11:56,570 You should follow those as well. 216 00:11:57,670 --> 00:12:00,450 Okay, let's rotate our emulator and see what happens. 217 00:12:01,730 --> 00:12:03,730 You can see that even though we've rotated, 218 00:12:03,730 --> 00:12:05,790 the state of the drawer remains the same. 219 00:12:05,790 --> 00:12:10,510 Which item is selected remains selected, and even if we were to hit home and 220 00:12:10,510 --> 00:12:13,760 come back to this app, the state would be saved and 221 00:12:13,760 --> 00:12:16,190 restored in the drawer when it comes back into view. 222 00:12:17,450 --> 00:12:18,260 In this workshop, 223 00:12:18,260 --> 00:12:22,700 we use the Android Studio Activity template to implement a navigation drawer. 224 00:12:22,700 --> 00:12:25,350 Since it's implemented using a simple drawer layout, 225 00:12:25,350 --> 00:12:28,980 you can include it in your app project in a way that suits your app the best. 226 00:12:28,980 --> 00:12:31,380 Simply include the Android support library, and 227 00:12:31,380 --> 00:12:33,930 the drawer layout would be included, as well. 228 00:12:33,930 --> 00:12:38,830 You can prefer views over fragments, provide custom colors and touch selectors, 229 00:12:38,830 --> 00:12:42,830 as well as the more modern toolbar component to use with drawer layout. 230 00:12:42,830 --> 00:12:45,450 Consider using a navigation drawer when it makes sense, and 231 00:12:45,450 --> 00:12:49,530 your users will benefit from easy access to the most important parts of your app.