OSDN Git Service

am 6e5dc4dd: am 0bf8c6f9: Merge "Doc update: CCS and notifications" into jb-mr1.1...
[android-x86/frameworks-base.git] / docs / html / training / implementing-navigation / nav-drawer.jd
1 page.title=Creating a Navigation Drawer
2
3 trainingnavtop=true
4
5 @jd:body
6
7 <div id="tb-wrapper">
8 <div id="tb">
9
10 <h2>This lesson teaches you to:</h2>
11 <ol>
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>
17 </ol>
18
19 <h2>Try it out</h2>
20
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>
25 </div>
26
27 </div>
28 </div>
29
30
31
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>
36
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>
40
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>
46 </div>
47
48
49 <h2 id="DrawerLayout">Create a Drawer Layout</h2>
50
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>
56
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>
61
62 <pre>
63 &lt;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     &lt;!-- The main content view -->
69     &lt;FrameLayout
70         android:id="@+id/content_frame"
71         android:layout_width="match_parent"
72         android:layout_height="match_parent" />
73     &lt;!-- The navigation drawer -->
74     &lt;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="&#64;android:color/transparent"
80         android:dividerHeight="0dp"
81         android:background="#111"/>
82 &lt;/android.support.v4.widget.DrawerLayout>
83 </pre>
84
85 <p>This layout demonstrates some important layout characteristics:</p>
86 <ul>
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>
98   </li>
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>
102 </ul>
103
104
105
106 <h2 id="Init">Initialize the Drawer List</h2>
107
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>
113
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>
116
117 <pre>
118 public class MainActivity extends Activity {
119     private String[] mPlanetTitles;
120     private ListView mDrawerList;
121     ...
122
123     &#64;Override
124     public void onCreate(Bundle savedInstanceState) {
125         super.onCreate(savedInstanceState);
126         setContentView(R.layout.activity_main);
127
128         mPlanetTitles = getResources().getStringArray(R.array.planets_array);
129         mDrawerList = (ListView) findViewById(R.id.left_drawer);
130
131         // Set the adapter for the list view
132         mDrawerList.setAdapter(new ArrayAdapter&lt;String>(this,
133                 R.layout.drawer_list_item, mPlanetTitles));
134         // Set the list's click listener
135         mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
136
137         ...
138     }
139 }
140 </pre>
141
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>
146
147
148
149 <h2 id="ListItemClicks">Handle Navigation Click Events</h2>
150
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>
155
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>
163
164 <pre>
165 private class DrawerItemClickListener implements ListView.OnItemClickListener {
166     &#64;Override
167     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
168         selectItem(position);
169     }
170 }
171
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);
179
180     // Insert the fragment by replacing any existing fragment
181     FragmentManager fragmentManager = getFragmentManager();
182     fragmentManager.beginTransaction()
183                    .replace(R.id.content_frame, fragment)
184                    .commit();
185
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);
190 }
191
192 &#64;Override
193 public void setTitle(CharSequence title) {
194     mTitle = title;
195     getActionBar().setTitle(mTitle);
196 }
197
198 </pre>
199
200
201
202
203 <h2 id="OpenClose">Listen for Open and Close Events</h2>
204
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>
212
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>
222
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>
229
230 <pre>
231 public class MainActivity extends Activity {
232     private DrawerLayout mDrawerLayout;
233     private ActionBarDrawerToggle mDrawerToggle;
234     private CharSequence mDrawerTitle;
235     private CharSequence mTitle;
236     ...
237
238     &#64;Override
239     public void onCreate(Bundle savedInstanceState) {
240         super.onCreate(savedInstanceState);
241         setContentView(R.layout.activity_main);
242         ...
243
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) {
248
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()
253             }
254
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()
259             }
260         };
261
262         // Set the drawer toggle as the DrawerListener
263         mDrawerLayout.setDrawerListener(mDrawerToggle);
264     }
265
266     /* Called whenever we call invalidateOptionsMenu() */
267     &#64;Override
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);
273     }
274 }
275 </pre>
276
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
279 action bar icon.</p>
280
281
282
283 <h2 id="ActionBarIcon">Open and Close with the App Icon</h2>
284
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>
291
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>
294 <ul>
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).
300 </ul>
301
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>
306
307 <pre>
308 public class MainActivity extends Activity {
309     private DrawerLayout mDrawerLayout;
310     private ActionBarDrawerToggle mDrawerToggle;
311     ...
312
313     public void onCreate(Bundle savedInstanceState) {
314         ...
315
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) {
319
320             /** Called when a drawer has settled in a completely closed state. */
321             public void onDrawerClosed(View view) {
322                 getActionBar().setTitle(mTitle);
323             }
324
325             /** Called when a drawer has settled in a completely open state. */
326             public void onDrawerOpened(View drawerView) {
327                 getActionBar().setTitle(mDrawerTitle);
328             }
329         };
330
331         // Set the drawer toggle as the DrawerListener
332         mDrawerLayout.setDrawerListener(mDrawerToggle);
333
334         getActionBar().setDisplayHomeAsUpEnabled(true);
335         getActionBar().setHomeButtonEnabled(true);
336     }
337
338     &#64;Override
339     protected void onPostCreate(Bundle savedInstanceState) {
340         super.onPostCreate(savedInstanceState);
341         // Sync the toggle state after onRestoreInstanceState has occurred.
342         mDrawerToggle.syncState();
343     }
344
345     &#64;Override
346     public void onConfigurationChanged(Configuration newConfig) {
347         super.onConfigurationChanged(newConfig);
348         mDrawerToggle.onConfigurationChanged(newConfig);
349     }
350
351     &#64;Override
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)) {
356           return true;
357         }
358         // Handle your other action bar items...
359
360         return super.onOptionsItemSelected(item);
361     }
362
363     ...
364 }
365 </pre>
366
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>