diff options
Diffstat (limited to 'docs/html/training/implementing-navigation/nav-drawer.jd')
-rw-r--r-- | docs/html/training/implementing-navigation/nav-drawer.jd | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/docs/html/training/implementing-navigation/nav-drawer.jd b/docs/html/training/implementing-navigation/nav-drawer.jd new file mode 100644 index 000000000000..da2b04614b0d --- /dev/null +++ b/docs/html/training/implementing-navigation/nav-drawer.jd @@ -0,0 +1,368 @@ +page.title=Creating a Navigation Drawer + +trainingnavtop=true + +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> + +<h2>This lesson teaches you to:</h2> +<ol> + <li><a href="#DrawerLayout">Create a Drawer Layout</a></li> + <li><a href="#Init">Initialize the Drawer List</a></li> + <li><a href="#ListItemClicks">Handle Navigation Click Events</a></li> + <li><a href="#OpenClose">Listen for Open and Close Events</a></li> + <li><a href="#ActionBarIcon">Open and Close with the App Icon</a></li> +</ol> + +<h2>Try it out</h2> + +<div class="download-box"> +<a href="http://developer.android.com/shareables/training/NavigationDrawer.zip" + class="button">Download the sample app</a> +<p class="filename">NavigationDrawer.zip</p> +</div> + +</div> +</div> + + + +<p>The navigation drawer is a panel that displays the app’s main navigation options +on the left edge of the screen. It is hidden most of the time, but is revealed +when the user swipes a finger from the left edge of the screen or, while at the top level of the +app, the user touches the app icon in the action bar.</p> + +<p>This lesson describes how to implement a navigation drawer using the +{@link android.support.v4.widget.DrawerLayout} APIs available in the +<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>.</p> + +<div class="note design"> +<p><strong>Navigation Drawer Design</strong></p> +<p>Before you decide to use a navigation drawer in your app, you should understand the use +cases and design principles defined in the +<a href="{@docRoot}design/patterns/navigation-drawers.html">Navigation Drawer</a> design guide.</p> +</div> + + +<h2 id="DrawerLayout">Create a Drawer Layout</h2> + +<p>To add a navigation drawer, declare your user interface with a +{@link android.support.v4.widget.DrawerLayout} object as the root view of your layout. +Inside the {@link android.support.v4.widget.DrawerLayout}, add one view that contains +the main content for the screen (your primary layout when the drawer is hidden) and another view +that contains the contents of the navigation drawer.</p> + +<p>For example, the following layout uses a {@link +android.support.v4.widget.DrawerLayout} with two child views: a {@link android.widget.FrameLayout} +to contain the main content (populated by a {@link android.app.Fragment} at +runtime), and a {@link android.widget.ListView} for the navigation drawer.</p> + +<pre> +<android.support.v4.widget.DrawerLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/drawer_layout" + android:layout_width="match_parent" + android:layout_height="match_parent"> + <!-- The main content view --> + <FrameLayout + android:id="@+id/content_frame" + android:layout_width="match_parent" + android:layout_height="match_parent" /> + <!-- The navigation drawer --> + <ListView android:id="@+id/left_drawer" + android:layout_width="240dp" + android:layout_height="match_parent" + android:layout_gravity="start" + android:choiceMode="singleChoice" + android:divider="@android:color/transparent" + android:dividerHeight="0dp" + android:background="#111"/> +</android.support.v4.widget.DrawerLayout> +</pre> + +<p>This layout demonstrates some important layout characteristics:</p> +<ul> + <li>The main content view (the {@link android.widget.FrameLayout} above) + <strong>must be the first child</strong> in the {@link + android.support.v4.widget.DrawerLayout} because the XML order implies z-ordering + and the drawer must be on top of the content.</li> + <li>The main content view is set to match the parent + view's width and height, because it represents the entire UI when the + navigation drawer is hidden.</li> + <li>The drawer view (the {@link android.widget.ListView}) <strong>must specify its horizontal + gravity</strong> with the {@code android:layout_gravity} attribute. To + support right-to-left (RTL) languages, specify the value with {@code "start"} + instead of {@code "left"} (so the drawer appears on the right when the layout is RTL).</p> + </li> + <li>The drawer view specifies its width in {@code dp} units and the height matches the parent + view. The drawer width should be no more than 320dp so the user can always + see a portion of the main content.</li> +</ul> + + + +<h2 id="Init">Initialize the Drawer List</h2> + +<p>In your activity, one of the first things to do is initialize +the navigation drawer's list of items. How you do so depends on the content of your app, but +a navigation drawer often consists of a {@link android.widget.ListView}, so the list +should be populated by an {@link android.widget.Adapter} (such as {@link +android.widget.ArrayAdapter} or {@link android.widget.SimpleCursorAdapter}).</p> + +<p>For example, here's how you can initialize the navigation list with a +<a href="{@docRoot}guide/topics/resources/string-resource.html#StringArray">string array</a>:</p> + +<pre> +public class MainActivity extends Activity { + private String[] mPlanetTitles; + private ListView mDrawerList; + ... + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + mPlanetTitles = getResources().getStringArray(R.array.planets_array); + mDrawerList = (ListView) findViewById(R.id.left_drawer); + + // Set the adapter for the list view + mDrawerList.setAdapter(new ArrayAdapter<String>(this, + R.layout.drawer_list_item, mPlanetTitles)); + // Set the list's click listener + mDrawerList.setOnItemClickListener(new DrawerItemClickListener()); + + ... + } +} +</pre> + +<p>This code also calls {@link android.widget.ListView#setOnItemClickListener +setOnItemClickListener()} to receive click events in the navigation drawer's list. +The next section shows how to implement this interface +and change the content view when the user selects an item.</p> + + + +<h2 id="ListItemClicks">Handle Navigation Click Events</h2> + +<p>When the user selects an item in the drawer's list, the system calls {@link +android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} on the +{@link android.widget.AdapterView.OnItemClickListener OnItemClickListener} given to +{@link android.widget.ListView#setOnItemClickListener setOnItemClickListener()}.</p> + +<p>What you do in the {@link +android.widget.AdapterView.OnItemClickListener#onItemClick onItemClick()} method +depends on how you've implemented your <a +href="{@docRoot}design/patterns/app-structure.html">app structure</a>. In the following example, +selecting each item in the list inserts a different {@link +android.app.Fragment} into the main content view (the +{@link android.widget.FrameLayout} element identified by the {@code R.id.content_frame} ID):</p> + +<pre> +private class DrawerItemClickListener implements ListView.OnItemClickListener { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + selectItem(position); + } +} + +/** Swaps fragments in the main content view */ +private void selectItem(int position) { + // Create a new fragment and specify the planet to show based on position + Fragment fragment = new PlanetFragment(); + Bundle args = new Bundle(); + args.putInt(PlanetFragment.ARG_PLANET_NUMBER, position); + fragment.setArguments(args); + + // Insert the fragment by replacing any existing fragment + FragmentManager fragmentManager = getFragmentManager(); + fragmentManager.beginTransaction() + .replace(R.id.content_frame, fragment) + .commit(); + + // Highlight the selected item, update the title, and close the drawer + mDrawer.setItemChecked(position, true); + setTitle(mPlanetTitles[position]); + mDrawerLayout.closeDrawer(mDrawer); +} + +@Override +public void setTitle(CharSequence title) { + mTitle = title; + getActionBar().setTitle(mTitle); +} + +</pre> + + + + +<h2 id="OpenClose">Listen for Open and Close Events</h2> + +<p>To listen for drawer open and close events, call {@link +android.support.v4.widget.DrawerLayout#setDrawerListener setDrawerListener()} on your +{@link android.support.v4.widget.DrawerLayout} and pass it an implementation of +{@link android.support.v4.widget.DrawerLayout.DrawerListener}. This interface provides callbacks +for drawer events such as {@link +android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerOpened onDrawerOpened()} and {@link +android.support.v4.widget.DrawerLayout.DrawerListener#onDrawerClosed onDrawerClosed()}.</p> + +<p>However, rather than implementing the {@link +android.support.v4.widget.DrawerLayout.DrawerListener}, if your activity includes the +<a href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you can instead +extend the {@link android.support.v4.app.ActionBarDrawerToggle} class. The +{@link android.support.v4.app.ActionBarDrawerToggle} implements +{@link android.support.v4.widget.DrawerLayout.DrawerListener} so you can still override those +callbacks, but it also facilitates the proper +interaction behavior between the action bar icon and the navigation drawer (discussed further in +the next section).</p> + +<p>As discussed in the <a href="{@docRoot}design/patterns/navigation-drawers.html">Navigation +Drawer</a> design guide, you should modify the contents of the action bar +when the drawer is visible, such as to change the title and remove action items that are +contextual to the main content. The following code shows how you can do so by overriding {@link +android.support.v4.widget.DrawerLayout.DrawerListener} callback methods with an instance +of the {@link android.support.v4.app.ActionBarDrawerToggle} class:</p> + +<pre> +public class MainActivity extends Activity { + private DrawerLayout mDrawerLayout; + private ActionBarDrawerToggle mDrawerToggle; + private CharSequence mDrawerTitle; + private CharSequence mTitle; + ... + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + ... + + mTitle = mDrawerTitle = getTitle(); + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, + R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) { + + /** Called when a drawer has settled in a completely closed state. */ + public void onDrawerClosed(View view) { + getActionBar().setTitle(mTitle); + invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() + } + + /** Called when a drawer has settled in a completely open state. */ + public void onDrawerOpened(View drawerView) { + getActionBar().setTitle(mDrawerTitle); + invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu() + } + }; + + // Set the drawer toggle as the DrawerListener + mDrawerLayout.setDrawerListener(mDrawerToggle); + } + + /* Called whenever we call invalidateOptionsMenu() */ + @Override + public boolean onPrepareOptionsMenu(Menu menu) { + // If the nav drawer is open, hide action items related to the content view + boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList); + menu.findItem(R.id.action_websearch).setVisible(!drawerOpen); + return super.onPrepareOptionsMenu(menu); + } +} +</pre> + +<p>The next section describes the {@link android.support.v4.app.ActionBarDrawerToggle} constructor +arguments and the other steps required to set it up to handle interaction with the +action bar icon.</p> + + + +<h2 id="ActionBarIcon">Open and Close with the App Icon</h2> + +<p>Users can open and close the navigation drawer with a swipe gesture from or towards the left +edge of the screen, but if you're using the <a +href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>, you should also allow users to +open and close it by touching the app icon. And the app icon should also indicate the presence of +the navigation drawer with a special icon. You can implement all this behavior by using the +{@link android.support.v4.app.ActionBarDrawerToggle} shown in the previous section.</p> + +<p>To make {@link android.support.v4.app.ActionBarDrawerToggle} work, create an instance of +it with its constructor, which requires the following arguments:</p> +<ul> + <li>The {@link android.app.Activity} hosting the drawer. + <li>The {@link android.support.v4.widget.DrawerLayout}. + <li>A drawable resource to use as the drawer indicator. + <li>A String resource to describe the "open drawer" action (for accessibility). + <li>A String resource to describe the "close drawer" action (for accessibility). +</ul> + +<p>Then, whether or not you've created a subclass of +{@link android.support.v4.app.ActionBarDrawerToggle} as your drawer listener, you need to call +upon your {@link android.support.v4.app.ActionBarDrawerToggle} in a few places throughout your +activity lifecycle:</p> + +<pre> +public class MainActivity extends Activity { + private DrawerLayout mDrawerLayout; + private ActionBarDrawerToggle mDrawerToggle; + ... + + public void onCreate(Bundle savedInstanceState) { + ... + + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, + R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) { + + /** Called when a drawer has settled in a completely closed state. */ + public void onDrawerClosed(View view) { + getActionBar().setTitle(mTitle); + } + + /** Called when a drawer has settled in a completely open state. */ + public void onDrawerOpened(View drawerView) { + getActionBar().setTitle(mDrawerTitle); + } + }; + + // Set the drawer toggle as the DrawerListener + mDrawerLayout.setDrawerListener(mDrawerToggle); + + getActionBar().setDisplayHomeAsUpEnabled(true); + getActionBar().setHomeButtonEnabled(true); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + // Sync the toggle state after onRestoreInstanceState has occurred. + mDrawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + mDrawerToggle.onConfigurationChanged(newConfig); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Pass the event to ActionBarDrawerToggle, if it returns + // true, then it has handled the app icon touch event + if (mDrawerToggle.onOptionsItemSelected(item)) { + return true; + } + // Handle your other action bar items... + + return super.onOptionsItemSelected(item); + } + + ... +} +</pre> + +<p>For a complete example of a navigation drawer, download the sample available at the +<a href="#top">top of the page</a>.</p>
\ No newline at end of file |