1 page.title=Creating a Navigation Drawer
2 page.tags="DrawerLayout", "navigation"
11 <h2>This lesson teaches you to:</h2>
13 <li><a href="#DrawerLayout">Create a Drawer Layout</a></li>
14 <li><a href="#Init">Initialize the Drawer List</a></li>
15 <li><a href="#ListItemClicks">Handle Navigation Click Events</a></li>
16 <li><a href="#OpenClose">Listen for Open and Close Events</a></li>
17 <li><a href="#ActionBarIcon">Open and Close with the App Icon</a></li>
22 <div class="download-box">
23 <a href="http://developer.android.com/shareables/training/NavigationDrawer.zip"
24 class="button">Download the sample app</a>
25 <p class="filename">NavigationDrawer.zip</p>
28 <div class="download-box">
29 <a href="http://developer.android.com/downloads/design/Android_Navigation_Drawer_Icon_20130516.zip"
30 class="button">Download the nav drawer icons</a>
31 <p class="filename">Android_Navigation_Drawer_Icon_20130516.zip</p>
39 <p>The navigation drawer is a panel that displays the app’s main navigation options
40 on the left edge of the screen. It is hidden most of the time, but is revealed
41 when the user swipes a finger from the left edge of the screen or, while at the top level of the
42 app, the user touches the app icon in the action bar.</p>
44 <p>This lesson describes how to implement a navigation drawer using the
45 {@link android.support.v4.widget.DrawerLayout} APIs available in the
46 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.</p>
48 <div class="note design">
49 <p><strong>Navigation Drawer Design</strong></p>
50 <p>Before you decide to use a navigation drawer in your app, you should understand the use
51 cases and design principles defined in the
52 <a href="{@docRoot}design/patterns/navigation-drawer.html">Navigation Drawer</a> design guide.</p>
56 <h2 id="DrawerLayout">Create a Drawer Layout</h2>
58 <p>To add a navigation drawer, declare your user interface with a
59 {@link android.support.v4.widget.DrawerLayout} object as the root view of your layout.
60 Inside the {@link android.support.v4.widget.DrawerLayout}, add one view that contains
61 the main content for the screen (your primary layout when the drawer is hidden) and another view
62 that contains the contents of the navigation drawer.</p>
64 <p>For example, the following layout uses a {@link
65 android.support.v4.widget.DrawerLayout} with two child views: a {@link android.widget.FrameLayout}
66 to contain the main content (populated by a {@link android.app.Fragment} at
67 runtime), and a {@link android.widget.ListView} for the navigation drawer.</p>
70 <android.support.v4.widget.DrawerLayout
71 xmlns:android="http://schemas.android.com/apk/res/android"
72 android:id="@+id/drawer_layout"
73 android:layout_width="match_parent"
74 android:layout_height="match_parent">
75 <!-- The main content view -->
77 android:id="@+id/content_frame"
78 android:layout_width="match_parent"
79 android:layout_height="match_parent" />
80 <!-- The navigation drawer -->
81 <ListView android:id="@+id/left_drawer"
82 android:layout_width="240dp"
83 android:layout_height="match_parent"
84 android:layout_gravity="start"
85 android:choiceMode="singleChoice"
86 android:divider="@android:color/transparent"
87 android:dividerHeight="0dp"
88 android:background="#111"/>
89 </android.support.v4.widget.DrawerLayout>
92 <p>This layout demonstrates some important layout characteristics:</p>
94 <li>The main content view (the {@link android.widget.FrameLayout} above)
95 <strong>must be the first child</strong> in the {@link
96 android.support.v4.widget.DrawerLayout} because the XML order implies z-ordering
97 and the drawer must be on top of the content.</li>
98 <li>The main content view is set to match the parent
99 view's width and height, because it represents the entire UI when the
100 navigation drawer is hidden.</li>
101 <li>The drawer view (the {@link android.widget.ListView}) <strong>must specify its horizontal
102 gravity</strong> with the {@code android:layout_gravity} attribute. To
103 support right-to-left (RTL) languages, specify the value with {@code "start"}
104 instead of {@code "left"} (so the drawer appears on the right when the layout is RTL).</p>
106 <li>The drawer view specifies its width in {@code dp} units and the height matches the parent
107 view. The drawer width should be no more than 320dp so the user can always
108 see a portion of the main content.</li>
113 <h2 id="Init">Initialize the Drawer List</h2>
115 <p>In your activity, one of the first things to do is initialize
116 the navigation drawer's list of items. How you do so depends on the content of your app, but
117 a navigation drawer often consists of a {@link android.widget.ListView}, so the list
118 should be populated by an {@link android.widget.Adapter} (such as {@link
119 android.widget.ArrayAdapter} or {@link android.widget.SimpleCursorAdapter}).</p>
121 <p>For example, here's how you can initialize the navigation list with a
122 <a href="{@docRoot}guide/topics/resources/string-resource.html#StringArray">string array</a>:</p>
125 public class MainActivity extends Activity {
126 private String[] mPlanetTitles;
127 private ListView mDrawerList;
131 public void onCreate(Bundle savedInstanceState) {
132 super.onCreate(savedInstanceState);
133 setContentView(R.layout.activity_main);
135 mPlanetTitles = getResources().getStringArray(R.array.planets_array);
136 mDrawerList = (ListView) findViewById(R.id.left_drawer);
138 // Set the adapter for the list view
139 mDrawerList.setAdapter(new ArrayAdapter<String>(this,
140 R.layout.drawer_list_item, mPlanetTitles));
141 // Set the list's click listener
142 mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
149 <p>This code also calls {@link android.widget.ListView#setOnItemClickListener
150 setOnItemClickListener()} to receive click events in the navigation drawer's list.
151 The next section shows how to implement this interface
152 and change the content view when the user selects an item.</p>
156 <h2 id="ListItemClicks">Handle Navigation Click Events</h2>
158 <p>When the user selects an item in the drawer's list, the system calls {@link
159 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
160 {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
161 {@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p>
163 <p>What you do in the {@link
164 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
165 depends on how you've implemented your <a
166 href="{@docRoot}design/patterns/app-structure.html">app structure</a>. In the following example,
167 selecting each item in the list inserts a different {@link
168 android.app.Fragment} into the main content view (the
169 {@link android.widget.FrameLayout} element identified by the {@code R.id.content_frame} ID):</p>
172 private class DrawerItemClickListener implements ListView.OnItemClickListener {
174 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
175 selectItem(position);
179 /** Swaps fragments in the main content view */
180 private void selectItem(int position) {
181 // Create a new fragment and specify the planet to show based on position
182 Fragment fragment = new PlanetFragment();
183 Bundle args = new Bundle();
184 args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
185 fragment.setArguments(args);
187 // Insert the fragment by replacing any existing fragment
188 FragmentManager fragmentManager = getFragmentManager();
189 fragmentManager.beginTransaction()
190 .replace(R.id.content_frame, fragment)
193 // Highlight the selected item, update the title, and close the drawer
194 mDrawer.setItemChecked(position, true);
195 setTitle(mPlanetTitles[position]);
196 mDrawerLayout.closeDrawer(mDrawer);
200 public void setTitle(CharSequence title) {
202 getActionBar().setTitle(mTitle);
210 <h2 id="OpenClose">Listen for Open and Close Events</h2>
212 <p>To listen for drawer open and close events, call {@link
213 android.support.v4.widget.DrawerLayout#setDrawerListener setDrawerListener()} on your
214 {@link android.support.v4.widget.DrawerLayout} and pass it an implementation of
215 {@link android.support.v4.widget.DrawerLayout.DrawerListener}. This interface provides callbacks
216 for drawer events such as {@link
217 android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerOpened onDrawerOpened()} and {@link
218 android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerClosed onDrawerClosed()}.</p>
220 <p>However, rather than implementing the {@link
221 android.support.v4.widget.DrawerLayout.DrawerListener}, if your activity includes the
222 <a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you can instead
223 extend the {@link android.support.v4.app.ActionBarDrawerToggle} class. The
224 {@link android.support.v4.app.ActionBarDrawerToggle} implements
225 {@link android.support.v4.widget.DrawerLayout.DrawerListener} so you can still override those
226 callbacks, but it also facilitates the proper
227 interaction behavior between the action bar icon and the navigation drawer (discussed further in
228 the next section).</p>
230 <p>As discussed in the <a href="{@docRoot}design/patterns/navigation-drawer.html">Navigation
231 Drawer</a> design guide, you should modify the contents of the action bar
232 when the drawer is visible, such as to change the title and remove action items that are
233 contextual to the main content. The following code shows how you can do so by overriding {@link
234 android.support.v4.widget.DrawerLayout.DrawerListener} callback methods with an instance
235 of the {@link android.support.v4.app.ActionBarDrawerToggle} class:</p>
238 public class MainActivity extends Activity {
239 private DrawerLayout mDrawerLayout;
240 private ActionBarDrawerToggle mDrawerToggle;
241 private CharSequence mDrawerTitle;
242 private CharSequence mTitle;
246 public void onCreate(Bundle savedInstanceState) {
247 super.onCreate(savedInstanceState);
248 setContentView(R.layout.activity_main);
251 mTitle = mDrawerTitle = getTitle();
252 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
253 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
254 R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
256 /** Called when a drawer has settled in a completely closed state. */
257 public void onDrawerClosed(View view) {
258 getActionBar().setTitle(mTitle);
259 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
262 /** Called when a drawer has settled in a completely open state. */
263 public void onDrawerOpened(View drawerView) {
264 getActionBar().setTitle(mDrawerTitle);
265 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
269 // Set the drawer toggle as the DrawerListener
270 mDrawerLayout.setDrawerListener(mDrawerToggle);
273 /* Called whenever we call invalidateOptionsMenu() */
275 public boolean onPrepareOptionsMenu(Menu menu) {
276 // If the nav drawer is open, hide action items related to the content view
277 boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
278 menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
279 return super.onPrepareOptionsMenu(menu);
284 <p>The next section describes the {@link android.support.v4.app.ActionBarDrawerToggle} constructor
285 arguments and the other steps required to set it up to handle interaction with the
290 <h2 id="ActionBarIcon">Open and Close with the App Icon</h2>
292 <p>Users can open and close the navigation drawer with a swipe gesture from or towards the left
293 edge of the screen, but if you're using the <a
294 href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you should also allow users to
295 open and close it by touching the app icon. And the app icon should also indicate the presence of
296 the navigation drawer with a special icon. You can implement all this behavior by using the
297 {@link android.support.v4.app.ActionBarDrawerToggle} shown in the previous section.</p>
299 <p>To make {@link android.support.v4.app.ActionBarDrawerToggle} work, create an instance of
300 it with its constructor, which requires the following arguments:</p>
302 <li>The {@link android.app.Activity} hosting the drawer.
303 <li>The {@link android.support.v4.widget.DrawerLayout}.
304 <li>A drawable resource to use as the drawer indicator.
305 <p><a href="http://developer.android.com/downloads/design/Android_Navigation_Drawer_Icon_20130516.zip"
306 >Download the standard navigation icons</a> (available for both dark and light themes).</p>
307 <li>A String resource to describe the "open drawer" action (for accessibility).
308 <li>A String resource to describe the "close drawer" action (for accessibility).
311 <p>Then, whether or not you've created a subclass of
312 {@link android.support.v4.app.ActionBarDrawerToggle} as your drawer listener, you need to call
313 upon your {@link android.support.v4.app.ActionBarDrawerToggle} in a few places throughout your
314 activity lifecycle:</p>
317 public class MainActivity extends Activity {
318 private DrawerLayout mDrawerLayout;
319 private ActionBarDrawerToggle mDrawerToggle;
322 public void onCreate(Bundle savedInstanceState) {
325 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
326 mDrawerToggle = new ActionBarDrawerToggle(
327 this, /* host Activity */
328 mDrawerLayout, /* DrawerLayout object */
329 R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */
330 R.string.drawer_open, /* "open drawer" description */
331 R.string.drawer_close /* "close drawer" description */
334 /** Called when a drawer has settled in a completely closed state. */
335 public void onDrawerClosed(View view) {
336 getActionBar().setTitle(mTitle);
339 /** Called when a drawer has settled in a completely open state. */
340 public void onDrawerOpened(View drawerView) {
341 getActionBar().setTitle(mDrawerTitle);
345 // Set the drawer toggle as the DrawerListener
346 mDrawerLayout.setDrawerListener(mDrawerToggle);
348 getActionBar().setDisplayHomeAsUpEnabled(true);
349 getActionBar().setHomeButtonEnabled(true);
353 protected void onPostCreate(Bundle savedInstanceState) {
354 super.onPostCreate(savedInstanceState);
355 // Sync the toggle state after onRestoreInstanceState has occurred.
356 mDrawerToggle.syncState();
360 public void onConfigurationChanged(Configuration newConfig) {
361 super.onConfigurationChanged(newConfig);
362 mDrawerToggle.onConfigurationChanged(newConfig);
366 public boolean onOptionsItemSelected(MenuItem item) {
367 // Pass the event to ActionBarDrawerToggle, if it returns
368 // true, then it has handled the app icon touch event
369 if (mDrawerToggle.onOptionsItemSelected(item)) {
372 // Handle your other action bar items...
374 return super.onOptionsItemSelected(item);
381 <p>For a complete example of a navigation drawer, download the sample available at the
382 <a href="#top">top of the page</a>.</p>