• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Creating a Navigation Drawer
2page.tags="DrawerLayout", "navigation"
3
4trainingnavtop=true
5
6@jd:body
7
8<div id="tb-wrapper">
9<div id="tb">
10
11<h2>This lesson teaches you to:</h2>
12<ol>
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>
18</ol>
19
20<h2>Try it out</h2>
21
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>
26</div>
27
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>
32</div>
33
34</div>
35</div>
36
37
38
39<p>The navigation drawer is a panel that displays the app’s main navigation options
40on the left edge of the screen. It is hidden most of the time, but is revealed
41when the user swipes a finger from the left edge of the screen or, while at the top level of the
42app, the user touches the app icon in the action bar.</p>
43
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>
47
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
51cases and design principles defined in the
52<a href="{@docRoot}design/patterns/navigation-drawer.html">Navigation Drawer</a> design guide.</p>
53</div>
54
55
56<h2 id="DrawerLayout">Create a Drawer Layout</h2>
57
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.
60Inside the {@link android.support.v4.widget.DrawerLayout}, add one view that contains
61the main content for the screen (your primary layout when the drawer is hidden) and another view
62that contains the contents of the navigation drawer.</p>
63
64<p>For example, the following layout uses a {@link
65android.support.v4.widget.DrawerLayout} with two child views: a {@link android.widget.FrameLayout}
66to contain the main content (populated by a {@link android.app.Fragment} at
67runtime), and a {@link android.widget.ListView} for the navigation drawer.</p>
68
69<pre>
70&lt;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    &lt;!-- The main content view -->
76    &lt;FrameLayout
77        android:id="@+id/content_frame"
78        android:layout_width="match_parent"
79        android:layout_height="match_parent" />
80    &lt;!-- The navigation drawer -->
81    &lt;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="&#64;android:color/transparent"
87        android:dividerHeight="0dp"
88        android:background="#111"/>
89&lt;/android.support.v4.widget.DrawerLayout>
90</pre>
91
92<p>This layout demonstrates some important layout characteristics:</p>
93<ul>
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>
105  </li>
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>
109</ul>
110
111
112
113<h2 id="Init">Initialize the Drawer List</h2>
114
115<p>In your activity, one of the first things to do is initialize
116the navigation drawer's list of items. How you do so depends on the content of your app, but
117a navigation drawer often consists of a {@link android.widget.ListView}, so the list
118should be populated by an {@link android.widget.Adapter} (such as {@link
119android.widget.ArrayAdapter} or {@link android.widget.SimpleCursorAdapter}).</p>
120
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>
123
124<pre>
125public class MainActivity extends Activity {
126    private String[] mPlanetTitles;
127    private ListView mDrawerList;
128    ...
129
130    &#64;Override
131    public void onCreate(Bundle savedInstanceState) {
132        super.onCreate(savedInstanceState);
133        setContentView(R.layout.activity_main);
134
135        mPlanetTitles = getResources().getStringArray(R.array.planets_array);
136        mDrawerList = (ListView) findViewById(R.id.left_drawer);
137
138        // Set the adapter for the list view
139        mDrawerList.setAdapter(new ArrayAdapter&lt;String>(this,
140                R.layout.drawer_list_item, mPlanetTitles));
141        // Set the list's click listener
142        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
143
144        ...
145    }
146}
147</pre>
148
149<p>This code also calls {@link android.widget.ListView#setOnItemClickListener
150setOnItemClickListener()} to receive click events in the navigation drawer's list.
151The next section shows how to implement this interface
152and change the content view when the user selects an item.</p>
153
154
155
156<h2 id="ListItemClicks">Handle Navigation Click Events</h2>
157
158<p>When the user selects an item in the drawer's list, the system calls {@link
159android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
160{@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
161{@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p>
162
163<p>What you do in the {@link
164android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
165depends on how you've implemented your <a
166href="{@docRoot}design/patterns/app-structure.html">app structure</a>. In the following example,
167selecting each item in the list inserts a different {@link
168android.app.Fragment} into the main content view (the
169{@link android.widget.FrameLayout} element identified by the {@code R.id.content_frame} ID):</p>
170
171<pre>
172private class DrawerItemClickListener implements ListView.OnItemClickListener {
173    &#64;Override
174    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
175        selectItem(position);
176    }
177}
178
179/** Swaps fragments in the main content view */
180private 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);
186
187    // Insert the fragment by replacing any existing fragment
188    FragmentManager fragmentManager = getFragmentManager();
189    fragmentManager.beginTransaction()
190                   .replace(R.id.content_frame, fragment)
191                   .commit();
192
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);
197}
198
199&#64;Override
200public void setTitle(CharSequence title) {
201    mTitle = title;
202    getActionBar().setTitle(mTitle);
203}
204
205</pre>
206
207
208
209
210<h2 id="OpenClose">Listen for Open and Close Events</h2>
211
212<p>To listen for drawer open and close events, call {@link
213android.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
216for drawer events such as {@link
217android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerOpened onDrawerOpened()} and {@link
218android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerClosed onDrawerClosed()}.</p>
219
220<p>However, rather than implementing the {@link
221android.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
223extend 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
226callbacks, but it also facilitates the proper
227interaction behavior between the action bar icon and the navigation drawer (discussed further in
228the next section).</p>
229
230<p>As discussed in the <a href="{@docRoot}design/patterns/navigation-drawer.html">Navigation
231Drawer</a> design guide, you should modify the contents of the action bar
232when the drawer is visible, such as to change the title and remove action items that are
233contextual to the main content. The following code shows how you can do so by overriding {@link
234android.support.v4.widget.DrawerLayout.DrawerListener} callback methods with an instance
235of the {@link android.support.v4.app.ActionBarDrawerToggle} class:</p>
236
237<pre>
238public class MainActivity extends Activity {
239    private DrawerLayout mDrawerLayout;
240    private ActionBarDrawerToggle mDrawerToggle;
241    private CharSequence mDrawerTitle;
242    private CharSequence mTitle;
243    ...
244
245    &#64;Override
246    public void onCreate(Bundle savedInstanceState) {
247        super.onCreate(savedInstanceState);
248        setContentView(R.layout.activity_main);
249        ...
250
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) {
255
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()
260            }
261
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()
266            }
267        };
268
269        // Set the drawer toggle as the DrawerListener
270        mDrawerLayout.setDrawerListener(mDrawerToggle);
271    }
272
273    /* Called whenever we call invalidateOptionsMenu() */
274    &#64;Override
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);
280    }
281}
282</pre>
283
284<p>The next section describes the {@link android.support.v4.app.ActionBarDrawerToggle} constructor
285arguments and the other steps required to set it up to handle interaction with the
286action bar icon.</p>
287
288
289
290<h2 id="ActionBarIcon">Open and Close with the App Icon</h2>
291
292<p>Users can open and close the navigation drawer with a swipe gesture from or towards the left
293edge of the screen, but if you're using the <a
294href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you should also allow users to
295open and close it by touching the app icon. And the app icon should also indicate the presence of
296the 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>
298
299<p>To make {@link android.support.v4.app.ActionBarDrawerToggle} work, create an instance of
300it with its constructor, which requires the following arguments:</p>
301<ul>
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).
309</ul>
310
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
313upon your {@link android.support.v4.app.ActionBarDrawerToggle} in a few places throughout your
314activity lifecycle:</p>
315
316<pre>
317public class MainActivity extends Activity {
318    private DrawerLayout mDrawerLayout;
319    private ActionBarDrawerToggle mDrawerToggle;
320    ...
321
322    public void onCreate(Bundle savedInstanceState) {
323        ...
324
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 */
332                ) {
333
334            /** Called when a drawer has settled in a completely closed state. */
335            public void onDrawerClosed(View view) {
336                getActionBar().setTitle(mTitle);
337            }
338
339            /** Called when a drawer has settled in a completely open state. */
340            public void onDrawerOpened(View drawerView) {
341                getActionBar().setTitle(mDrawerTitle);
342            }
343        };
344
345        // Set the drawer toggle as the DrawerListener
346        mDrawerLayout.setDrawerListener(mDrawerToggle);
347
348        getActionBar().setDisplayHomeAsUpEnabled(true);
349        getActionBar().setHomeButtonEnabled(true);
350    }
351
352    &#64;Override
353    protected void onPostCreate(Bundle savedInstanceState) {
354        super.onPostCreate(savedInstanceState);
355        // Sync the toggle state after onRestoreInstanceState has occurred.
356        mDrawerToggle.syncState();
357    }
358
359    &#64;Override
360    public void onConfigurationChanged(Configuration newConfig) {
361        super.onConfigurationChanged(newConfig);
362        mDrawerToggle.onConfigurationChanged(newConfig);
363    }
364
365    &#64;Override
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)) {
370          return true;
371        }
372        // Handle your other action bar items...
373
374        return super.onOptionsItemSelected(item);
375    }
376
377    ...
378}
379</pre>
380
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>
383