Home | History | Annotate | Download | only in implementing-navigation
      1 page.title=Creating a Navigation Drawer
      2 page.tags=DrawerLayout,navigation
      3 
      4 trainingnavtop=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 apps 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>
     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
     51 cases 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.
     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>
     63 
     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>
     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
    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>
    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>
    125 public class MainActivity extends Activity {
    126     private String[] mPlanetTitles;
    127     private DrawerLayout mDrawerLayout;
    128     private ListView mDrawerList;
    129     ...
    130 
    131     &#64;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&lt;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.AdapterView#setOnItemClickListener
    152 setOnItemClickListener()} to receive click events in the navigation drawer's list.
    153 The next section shows how to implement this interface
    154 and 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
    161 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the
    162 {@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to
    163 {@link android.widget.AdapterView#setOnItemClickListener setOnItemClickListener()}.</p>
    164 
    165 <p>What you do in the {@link
    166 android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method
    167 depends on how you've implemented your <a
    168 href="{@docRoot}design/patterns/app-structure.html">app structure</a>. In the following example,
    169 selecting each item in the list inserts a different {@link
    170 android.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>
    174 private class DrawerItemClickListener implements ListView.OnItemClickListener {
    175     &#64;Override
    176     public void onItemClick(AdapterView&lt;?> parent, View view, int position, long id) {
    177         selectItem(position);
    178     }
    179 }
    180 
    181 /** Swaps fragments in the main content view */
    182 private 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 &#64;Override
    202 public 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
    215 android.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
    218 for drawer events such as {@link
    219 android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerOpened onDrawerOpened()} and {@link
    220 android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerClosed onDrawerClosed()}.</p>
    221 
    222 <p>However, rather than implementing the {@link
    223 android.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
    225 extend 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
    228 callbacks, but it also facilitates the proper
    229 interaction behavior between the action bar icon and the navigation drawer (discussed further in
    230 the next section).</p>
    231 
    232 <p>As discussed in the <a href="{@docRoot}design/patterns/navigation-drawer.html">Navigation
    233 Drawer</a> design guide, you should modify the contents of the action bar
    234 when the drawer is visible, such as to change the title and remove action items that are
    235 contextual to the main content. The following code shows how you can do so by overriding {@link
    236 android.support.v4.widget.DrawerLayout.DrawerListener} callback methods with an instance
    237 of the {@link android.support.v4.app.ActionBarDrawerToggle} class:</p>
    238 
    239 <pre>
    240 public class MainActivity extends Activity {
    241     private DrawerLayout mDrawerLayout;
    242     private ActionBarDrawerToggle mDrawerToggle;
    243     private CharSequence mDrawerTitle;
    244     private CharSequence mTitle;
    245     ...
    246 
    247     &#64;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     &#64;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
    289 arguments and the other steps required to set it up to handle interaction with the
    290 action 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
    297 edge of the screen, but if you're using the <a
    298 href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you should also allow users to
    299 open and close it by touching the app icon. And the app icon should also indicate the presence of
    300 the 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
    304 it 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
    317 upon your {@link android.support.v4.app.ActionBarDrawerToggle} in a few places throughout your
    318 activity lifecycle:</p>
    319 
    320 <pre>
    321 public 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     &#64;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     &#64;Override
    366     public void onConfigurationChanged(Configuration newConfig) {
    367         super.onConfigurationChanged(newConfig);
    368         mDrawerToggle.onConfigurationChanged(newConfig);
    369     }
    370 
    371     &#64;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