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_Design_Icons_20130926.zip" 30 class="button">Download the Action Bar Icon Pack</a> 31<p class="filename">Android_Design_Icons_20130926.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/support-library/index.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<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 --> 76 <FrameLayout 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> 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 DrawerLayout mDrawerLayout; 128 private ListView mDrawerList; 129 ... 130 131 @Override 132 public void onCreate(Bundle savedInstanceState) { 133 super.onCreate(savedInstanceState); 134 setContentView(R.layout.activity_main); 135 136 mPlanetTitles = getResources().getStringArray(R.array.planets_array); 137 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 138 mDrawerList = (ListView) findViewById(R.id.left_drawer); 139 140 // Set the adapter for the list view 141 mDrawerList.setAdapter(new ArrayAdapter<String>(this, 142 R.layout.drawer_list_item, mPlanetTitles)); 143 // Set the list's click listener 144 mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); 145 146 ... 147 } 148} 149</pre> 150 151<p>This code also calls {@link android.widget.ListView#setOnItemClickListener 152setOnItemClickListener()} to receive click events in the navigation drawer's list. 153The next section shows how to implement this interface 154and change the content view when the user selects an item.</p> 155 156 157 158<h2 id="ListItemClicks">Handle Navigation Click Events</h2> 159 160<p>When the user selects an item in the drawer's list, the system calls {@link 161android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the 162{@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to 163{@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p> 164 165<p>What you do in the {@link 166android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method 167depends on how you've implemented your <a 168href="{@docRoot}design/patterns/app-structure.html">app structure</a>. In the following example, 169selecting each item in the list inserts a different {@link 170android.app.Fragment} into the main content view (the 171{@link android.widget.FrameLayout} element identified by the {@code R.id.content_frame} ID):</p> 172 173<pre> 174private class DrawerItemClickListener implements ListView.OnItemClickListener { 175 @Override 176 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 177 selectItem(position); 178 } 179} 180 181/** Swaps fragments in the main content view */ 182private void selectItem(int position) { 183 // Create a new fragment and specify the planet to show based on position 184 Fragment fragment = new PlanetFragment(); 185 Bundle args = new Bundle(); 186 args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position); 187 fragment.setArguments(args); 188 189 // Insert the fragment by replacing any existing fragment 190 FragmentManager fragmentManager = getFragmentManager(); 191 fragmentManager.beginTransaction() 192 .replace(R.id.content_frame, fragment) 193 .commit(); 194 195 // Highlight the selected item, update the title, and close the drawer 196 mDrawerList.setItemChecked(position, true); 197 setTitle(mPlanetTitles[position]); 198 mDrawerLayout.closeDrawer(mDrawerList); 199} 200 201@Override 202public void setTitle(CharSequence title) { 203 mTitle = title; 204 getActionBar().setTitle(mTitle); 205} 206 207</pre> 208 209 210 211 212<h2 id="OpenClose">Listen for Open and Close Events</h2> 213 214<p>To listen for drawer open and close events, call {@link 215android.support.v4.widget.DrawerLayout#setDrawerListener setDrawerListener()} on your 216{@link android.support.v4.widget.DrawerLayout} and pass it an implementation of 217{@link android.support.v4.widget.DrawerLayout.DrawerListener}. This interface provides callbacks 218for drawer events such as {@link 219android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerOpened onDrawerOpened()} and {@link 220android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerClosed onDrawerClosed()}.</p> 221 222<p>However, rather than implementing the {@link 223android.support.v4.widget.DrawerLayout.DrawerListener}, if your activity includes the 224<a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you can instead 225extend the {@link android.support.v4.app.ActionBarDrawerToggle} class. The 226{@link android.support.v4.app.ActionBarDrawerToggle} implements 227{@link android.support.v4.widget.DrawerLayout.DrawerListener} so you can still override those 228callbacks, but it also facilitates the proper 229interaction behavior between the action bar icon and the navigation drawer (discussed further in 230the next section).</p> 231 232<p>As discussed in the <a href="{@docRoot}design/patterns/navigation-drawer.html">Navigation 233Drawer</a> design guide, you should modify the contents of the action bar 234when the drawer is visible, such as to change the title and remove action items that are 235contextual to the main content. The following code shows how you can do so by overriding {@link 236android.support.v4.widget.DrawerLayout.DrawerListener} callback methods with an instance 237of the {@link android.support.v4.app.ActionBarDrawerToggle} class:</p> 238 239<pre> 240public class MainActivity extends Activity { 241 private DrawerLayout mDrawerLayout; 242 private ActionBarDrawerToggle mDrawerToggle; 243 private CharSequence mDrawerTitle; 244 private CharSequence mTitle; 245 ... 246 247 @Override 248 public void onCreate(Bundle savedInstanceState) { 249 super.onCreate(savedInstanceState); 250 setContentView(R.layout.activity_main); 251 ... 252 253 mTitle = mDrawerTitle = getTitle(); 254 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 255 mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 256 R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) { 257 258 /** Called when a drawer has settled in a completely closed state. */ 259 public void onDrawerClosed(View view) { 260 super.onDrawerClosed(view); 261 getActionBar().setTitle(mTitle); 262 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() 263 } 264 265 /** Called when a drawer has settled in a completely open state. */ 266 public void onDrawerOpened(View drawerView) { 267 super.onDrawerOpened(drawerView); 268 getActionBar().setTitle(mDrawerTitle); 269 invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() 270 } 271 }; 272 273 // Set the drawer toggle as the DrawerListener 274 mDrawerLayout.setDrawerListener(mDrawerToggle); 275 } 276 277 /* Called whenever we call invalidateOptionsMenu() */ 278 @Override 279 public boolean onPrepareOptionsMenu(Menu menu) { 280 // If the nav drawer is open, hide action items related to the content view 281 boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); 282 menu.findItem(R.id.action_websearch).setVisible(!drawerOpen); 283 return super.onPrepareOptionsMenu(menu); 284 } 285} 286</pre> 287 288<p>The next section describes the {@link android.support.v4.app.ActionBarDrawerToggle} constructor 289arguments and the other steps required to set it up to handle interaction with the 290action bar icon.</p> 291 292 293 294<h2 id="ActionBarIcon">Open and Close with the App Icon</h2> 295 296<p>Users can open and close the navigation drawer with a swipe gesture from or towards the left 297edge of the screen, but if you're using the <a 298href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you should also allow users to 299open and close it by touching the app icon. And the app icon should also indicate the presence of 300the navigation drawer with a special icon. You can implement all this behavior by using the 301{@link android.support.v4.app.ActionBarDrawerToggle} shown in the previous section.</p> 302 303<p>To make {@link android.support.v4.app.ActionBarDrawerToggle} work, create an instance of 304it with its constructor, which requires the following arguments:</p> 305<ul> 306 <li>The {@link android.app.Activity} hosting the drawer. 307 <li>The {@link android.support.v4.widget.DrawerLayout}. 308 <li>A drawable resource to use as the drawer indicator. 309 <p>The standard navigation drawer icon is available in the <a href="http://developer.android.com/downloads/design/Android_Design_Icons_20130926.zip" 310>Download the Action Bar Icon Pack</a>.</p> 311 <li>A String resource to describe the "open drawer" action (for accessibility). 312 <li>A String resource to describe the "close drawer" action (for accessibility). 313</ul> 314 315<p>Then, whether or not you've created a subclass of 316{@link android.support.v4.app.ActionBarDrawerToggle} as your drawer listener, you need to call 317upon your {@link android.support.v4.app.ActionBarDrawerToggle} in a few places throughout your 318activity lifecycle:</p> 319 320<pre> 321public class MainActivity extends Activity { 322 private DrawerLayout mDrawerLayout; 323 private ActionBarDrawerToggle mDrawerToggle; 324 ... 325 326 public void onCreate(Bundle savedInstanceState) { 327 ... 328 329 mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); 330 mDrawerToggle = new ActionBarDrawerToggle( 331 this, /* host Activity */ 332 mDrawerLayout, /* DrawerLayout object */ 333 R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */ 334 R.string.drawer_open, /* "open drawer" description */ 335 R.string.drawer_close /* "close drawer" description */ 336 ) { 337 338 /** Called when a drawer has settled in a completely closed state. */ 339 public void onDrawerClosed(View view) { 340 super.onDrawerClosed(view); 341 getActionBar().setTitle(mTitle); 342 } 343 344 /** Called when a drawer has settled in a completely open state. */ 345 public void onDrawerOpened(View drawerView) { 346 super.onDrawerOpened(drawerView); 347 getActionBar().setTitle(mDrawerTitle); 348 } 349 }; 350 351 // Set the drawer toggle as the DrawerListener 352 mDrawerLayout.setDrawerListener(mDrawerToggle); 353 354 getActionBar().setDisplayHomeAsUpEnabled(true); 355 getActionBar().setHomeButtonEnabled(true); 356 } 357 358 @Override 359 protected void onPostCreate(Bundle savedInstanceState) { 360 super.onPostCreate(savedInstanceState); 361 // Sync the toggle state after onRestoreInstanceState has occurred. 362 mDrawerToggle.syncState(); 363 } 364 365 @Override 366 public void onConfigurationChanged(Configuration newConfig) { 367 super.onConfigurationChanged(newConfig); 368 mDrawerToggle.onConfigurationChanged(newConfig); 369 } 370 371 @Override 372 public boolean onOptionsItemSelected(MenuItem item) { 373 // Pass the event to ActionBarDrawerToggle, if it returns 374 // true, then it has handled the app icon touch event 375 if (mDrawerToggle.onOptionsItemSelected(item)) { 376 return true; 377 } 378 // Handle your other action bar items... 379 380 return super.onOptionsItemSelected(item); 381 } 382 383 ... 384} 385</pre> 386 387<p>For a complete example of a navigation drawer, download the sample available at the 388<a href="#top">top of the page</a>.</p> 389