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<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 ListView mDrawerList; 128 ... 129 130 @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<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 @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@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 @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 @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 @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 @Override 360 public void onConfigurationChanged(Configuration newConfig) { 361 super.onConfigurationChanged(newConfig); 362 mDrawerToggle.onConfigurationChanged(newConfig); 363 } 364 365 @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