1 page.title=Creating a Navigation Drawer
10 <h2>This lesson teaches you to:</h2>
12 <li><a href="#DrawerLayout">Create a Drawer Layout</a></li>
13 <li><a href="#Init">Initialize the Drawer List</a></li>
14 <li><a href="#ListItemClicks">Handle Navigation Click Events</a></li>
15 <li><a href="#OpenClose">Listen for Open and Close Events</a></li>
16 <li><a href="#ActionBarIcon">Open and Close with the App Icon</a></li>
21 <div class="download-box">
22 <a href="http://developer.android.com/shareables/training/NavigationDrawer.zip"
23 class="button">Download the sample app</a>
24 <p class="filename">NavigationDrawer.zip</p>
32 <p>The navigation drawer is a panel that displays the app’s main navigation options
33 on the left edge of the screen. It is hidden most of the time, but is revealed
34 when the user swipes a finger from the left edge of the screen or, while at the top level of the
35 app, the user touches the app icon in the action bar.</p>
37 <p>This lesson describes how to implement a navigation drawer using the
38 {@link android.support.v4.widget.DrawerLayout} APIs available in the
39 <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.</p>
41 <div class="note design">
42 <p><strong>Navigation Drawer Design</strong></p>
43 <p>Before you decide to use a navigation drawer in your app, you should understand the use
44 cases and design principles defined in the
45 <a href="{@docRoot}design/patterns/navigation-drawers.html">Navigation Drawer</a> design guide.</p>
49 <h2 id="DrawerLayout">Create a Drawer Layout</h2>
51 <p>To add a navigation drawer, declare your user interface with a
52 {@link android.support.v4.widget.DrawerLayout} object as the root view of your layout.
53 Inside the {@link android.support.v4.widget.DrawerLayout}, add one view that contains
54 the main content for the screen (your primary layout when the drawer is hidden) and another view
55 that contains the contents of the navigation drawer.</p>
57 <p>For example, the following layout uses a {@link
58 android.support.v4.widget.DrawerLayout} with two child views: a {@link android.widget.FrameLayout}
59 to contain the main content (populated by a {@link android.app.Fragment} at
60 runtime), and a {@link android.widget.ListView} for the navigation drawer.</p>
63 <android.support.v4.widget.DrawerLayout
64 xmlns:android="http://schemas.android.com/apk/res/android"
65 android:id="@+id/drawer_layout"
66 android:layout_width="match_parent"
67 android:layout_height="match_parent">
68 <!-- The main content view -->
70 android:id="@+id/content_frame"
71 android:layout_width="match_parent"
72 android:layout_height="match_parent" />
73 <!-- The navigation drawer -->
74 <ListView android:id="@+id/left_drawer"
75 android:layout_width="240dp"
76 android:layout_height="match_parent"
77 android:layout_gravity="start"
78 android:choiceMode="singleChoice"
79 android:divider="@android:color/transparent"
80 android:dividerHeight="0dp"
81 android:background="#111"/>
82 </android.support.v4.widget.DrawerLayout>
85 <p>This layout demonstrates some important layout characteristics:</p>
87 <li>The main content view (the {@link android.widget.FrameLayout} above)
88 <strong>must be the first child</strong> in the {@link
89 android.support.v4.widget.DrawerLayout} because the XML order implies z-ordering
90 and the drawer must be on top of the content.</li>
91 <li>The main content view is set to match the parent
92 view's width and height, because it represents the entire UI when the
93 navigation drawer is hidden.</li>
94 <li>The drawer view (the {@link android.widget.ListView}) <strong>must specify its horizontal
95 gravity</strong> with the {@code android:layout_gravity} attribute. To
96 support right-to-left (RTL) languages, specify the value with {@code "start"}
97 instead of {@code "left"} (so the drawer appears on the right when the layout is RTL).</p>
99 <li>The drawer view specifies its width in {@code dp} units and the height matches the parent
100 view. The drawer width should be no more than 320dp so the user can always
101 see a portion of the main content.</li>
106 <h2 id="Init">Initialize the Drawer List</h2>
108 <p>In your activity, one of the first things to do is initialize
109 the navigation drawer's list of items. How you do so depends on the content of your app, but
110 a navigation drawer often consists of a {@link android.widget.ListView}, so the list
111 should be populated by an {@link android.widget.Adapter} (such as {@link
112 android.widget.ArrayAdapter} or {@link android.widget.SimpleCursorAdapter}).</p>
114 <p>For example, here's how you can initialize the navigation list with a
115 <a href="{@docRoot}guide/topics/resources/string-resource.html#StringArray">string array</a>:</p>
118 public class MainActivity extends Activity {
119 private String[] mPlanetTitles;
120 private ListView mDrawerList;
124 public void onCreate(Bundle savedInstanceState) {
125 super.onCreate(savedInstanceState);
126 setContentView(R.layout.activity_main);
128 mPlanetTitles = getResources().getStringArray(R.array.planets_array);
129 mDrawerList = (ListView) findViewById(R.id.left_drawer);
131 // Set the adapter for the list view
132 mDrawerList.setAdapter(new ArrayAdapter<String>(this,
133 R.layout.drawer_list_item, mPlanetTitles));
134 // Set the list's click listener
135 mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
142 <p>This code also calls {@link android.widget.ListView#setOnItemClickListener
143 setOnItemClickListener()} to receive click events in the navigation drawer's list.
144 The next section shows how to implement this interface
145 and change the content view when the user selects an item.</p>
149 <h2 id="ListItemClicks">Handle Navigation Click Events</h2>
151 <p>When the user selects an item in the drawer's list, the system calls {@link
152 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
153 {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
154 {@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p>
156 <p>What you do in the {@link
157 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
158 depends on how you've implemented your <a
159 href="{@docRoot}design/patterns/app-structure.html">app structure</a>. In the following example,
160 selecting each item in the list inserts a different {@link
161 android.app.Fragment} into the main content view (the
162 {@link android.widget.FrameLayout} element identified by the {@code R.id.content_frame} ID):</p>
165 private class DrawerItemClickListener implements ListView.OnItemClickListener {
167 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
168 selectItem(position);
172 /** Swaps fragments in the main content view */
173 private void selectItem(int position) {
174 // Create a new fragment and specify the planet to show based on position
175 Fragment fragment = new PlanetFragment();
176 Bundle args = new Bundle();
177 args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position);
178 fragment.setArguments(args);
180 // Insert the fragment by replacing any existing fragment
181 FragmentManager fragmentManager = getFragmentManager();
182 fragmentManager.beginTransaction()
183 .replace(R.id.content_frame, fragment)
186 // Highlight the selected item, update the title, and close the drawer
187 mDrawer.setItemChecked(position, true);
188 setTitle(mPlanetTitles[position]);
189 mDrawerLayout.closeDrawer(mDrawer);
193 public void setTitle(CharSequence title) {
195 getActionBar().setTitle(mTitle);
203 <h2 id="OpenClose">Listen for Open and Close Events</h2>
205 <p>To listen for drawer open and close events, call {@link
206 android.support.v4.widget.DrawerLayout#setDrawerListener setDrawerListener()} on your
207 {@link android.support.v4.widget.DrawerLayout} and pass it an implementation of
208 {@link android.support.v4.widget.DrawerLayout.DrawerListener}. This interface provides callbacks
209 for drawer events such as {@link
210 android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerOpened onDrawerOpened()} and {@link
211 android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerClosed onDrawerClosed()}.</p>
213 <p>However, rather than implementing the {@link
214 android.support.v4.widget.DrawerLayout.DrawerListener}, if your activity includes the
215 <a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you can instead
216 extend the {@link android.support.v4.app.ActionBarDrawerToggle} class. The
217 {@link android.support.v4.app.ActionBarDrawerToggle} implements
218 {@link android.support.v4.widget.DrawerLayout.DrawerListener} so you can still override those
219 callbacks, but it also facilitates the proper
220 interaction behavior between the action bar icon and the navigation drawer (discussed further in
221 the next section).</p>
223 <p>As discussed in the <a href="{@docRoot}design/patterns/navigation-drawers.html">Navigation
224 Drawer</a> design guide, you should modify the contents of the action bar
225 when the drawer is visible, such as to change the title and remove action items that are
226 contextual to the main content. The following code shows how you can do so by overriding {@link
227 android.support.v4.widget.DrawerLayout.DrawerListener} callback methods with an instance
228 of the {@link android.support.v4.app.ActionBarDrawerToggle} class:</p>
231 public class MainActivity extends Activity {
232 private DrawerLayout mDrawerLayout;
233 private ActionBarDrawerToggle mDrawerToggle;
234 private CharSequence mDrawerTitle;
235 private CharSequence mTitle;
239 public void onCreate(Bundle savedInstanceState) {
240 super.onCreate(savedInstanceState);
241 setContentView(R.layout.activity_main);
244 mTitle = mDrawerTitle = getTitle();
245 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
246 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
247 R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
249 /** Called when a drawer has settled in a completely closed state. */
250 public void onDrawerClosed(View view) {
251 getActionBar().setTitle(mTitle);
252 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
255 /** Called when a drawer has settled in a completely open state. */
256 public void onDrawerOpened(View drawerView) {
257 getActionBar().setTitle(mDrawerTitle);
258 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
262 // Set the drawer toggle as the DrawerListener
263 mDrawerLayout.setDrawerListener(mDrawerToggle);
266 /* Called whenever we call invalidateOptionsMenu() */
268 public boolean onPrepareOptionsMenu(Menu menu) {
269 // If the nav drawer is open, hide action items related to the content view
270 boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
271 menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
272 return super.onPrepareOptionsMenu(menu);
277 <p>The next section describes the {@link android.support.v4.app.ActionBarDrawerToggle} constructor
278 arguments and the other steps required to set it up to handle interaction with the
283 <h2 id="ActionBarIcon">Open and Close with the App Icon</h2>
285 <p>Users can open and close the navigation drawer with a swipe gesture from or towards the left
286 edge of the screen, but if you're using the <a
287 href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you should also allow users to
288 open and close it by touching the app icon. And the app icon should also indicate the presence of
289 the navigation drawer with a special icon. You can implement all this behavior by using the
290 {@link android.support.v4.app.ActionBarDrawerToggle} shown in the previous section.</p>
292 <p>To make {@link android.support.v4.app.ActionBarDrawerToggle} work, create an instance of
293 it with its constructor, which requires the following arguments:</p>
295 <li>The {@link android.app.Activity} hosting the drawer.
296 <li>The {@link android.support.v4.widget.DrawerLayout}.
297 <li>A drawable resource to use as the drawer indicator.
298 <li>A String resource to describe the "open drawer" action (for accessibility).
299 <li>A String resource to describe the "close drawer" action (for accessibility).
302 <p>Then, whether or not you've created a subclass of
303 {@link android.support.v4.app.ActionBarDrawerToggle} as your drawer listener, you need to call
304 upon your {@link android.support.v4.app.ActionBarDrawerToggle} in a few places throughout your
305 activity lifecycle:</p>
308 public class MainActivity extends Activity {
309 private DrawerLayout mDrawerLayout;
310 private ActionBarDrawerToggle mDrawerToggle;
313 public void onCreate(Bundle savedInstanceState) {
316 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
317 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
318 R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
320 /** Called when a drawer has settled in a completely closed state. */
321 public void onDrawerClosed(View view) {
322 getActionBar().setTitle(mTitle);
325 /** Called when a drawer has settled in a completely open state. */
326 public void onDrawerOpened(View drawerView) {
327 getActionBar().setTitle(mDrawerTitle);
331 // Set the drawer toggle as the DrawerListener
332 mDrawerLayout.setDrawerListener(mDrawerToggle);
334 getActionBar().setDisplayHomeAsUpEnabled(true);
335 getActionBar().setHomeButtonEnabled(true);
339 protected void onPostCreate(Bundle savedInstanceState) {
340 super.onPostCreate(savedInstanceState);
341 // Sync the toggle state after onRestoreInstanceState has occurred.
342 mDrawerToggle.syncState();
346 public void onConfigurationChanged(Configuration newConfig) {
347 super.onConfigurationChanged(newConfig);
348 mDrawerToggle.onConfigurationChanged(newConfig);
352 public boolean onOptionsItemSelected(MenuItem item) {
353 // Pass the event to ActionBarDrawerToggle, if it returns
354 // true, then it has handled the app icon touch event
355 if (mDrawerToggle.onOptionsItemSelected(item)) {
358 // Handle your other action bar items...
360 return super.onOptionsItemSelected(item);
367 <p>For a complete example of a navigation drawer, download the sample available at the
368 <a href="#top">top of the page</a>.</p>