which now includes the nav drawer icon Change-Id: I0d6452fa5b4856b96268763141d74dd8f83c221d
385 lines
16 KiB
Plaintext
385 lines
16 KiB
Plaintext
page.title=Creating a Navigation Drawer
|
||
page.tags="DrawerLayout", "navigation"
|
||
|
||
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 class="download-box">
|
||
<a href="http://developer.android.com/downloads/design/Android_Design_Icons_20130926.zip"
|
||
class="button">Download the Action Bar Icon Pack</a>
|
||
<p class="filename">Android_Design_Icons_20130926.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/support-library/index.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-drawer.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 DrawerLayout mDrawerLayout;
|
||
private ListView mDrawerList;
|
||
...
|
||
|
||
@Override
|
||
public void onCreate(Bundle savedInstanceState) {
|
||
super.onCreate(savedInstanceState);
|
||
setContentView(R.layout.activity_main);
|
||
|
||
mPlanetTitles = getResources().getStringArray(R.array.planets_array);
|
||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||
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
|
||
mDrawerList.setItemChecked(position, true);
|
||
setTitle(mPlanetTitles[position]);
|
||
mDrawerLayout.closeDrawer(mDrawerList);
|
||
}
|
||
|
||
@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-drawer.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.
|
||
<p>The standard navigation drawer icon is available in the <a href="http://developer.android.com/downloads/design/Android_Design_Icons_20130926.zip"
|
||
>Download the Action Bar Icon Pack</a>.</p>
|
||
<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, /* host Activity */
|
||
mDrawerLayout, /* DrawerLayout object */
|
||
R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */
|
||
R.string.drawer_open, /* "open drawer" description */
|
||
R.string.drawer_close /* "close drawer" description */
|
||
) {
|
||
|
||
/** 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>
|