-page.title=Implementing Ancestral Navigation
-parent.title=Implementing Effective Navigation
-parent.link=index.html
+page.title=Providing Up Navigation
trainingnavtop=true
-previous.title=Implementing Lateral Navigation
-previous.link=lateral.html
-next.title=Implementing Temporal Navigation
-next.link=temporal.html
@jd:body
<h2>This lesson teaches you to:</h2>
<ol>
- <li><a href="#up">Implement <em>Up</em> Navigation</a></li>
- <li><a href="#app-home">Properly Handle the Application Home Screen</a></li>
+ <li><a href="#SpecifyParent">Specify the Parent Activity</a></li>
+ <li><a href="#up">Add Up Action</a></li>
+ <li><a href="#NavigateUp">Navigate Up to Parent Activity</a></li>
</ol>
<h2>You should also read</h2>
</div>
-<p><em>Ancestral navigation</em> is up the application's information hierarchy, where the top of the hierarchy (or root) is the application's home screen. This navigation concept is described in <a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Designing Effective Navigation</a>. This lesson discusses how to provide ancestral navigation using the <em>Up</em> button in the action bar.</p>
+<p>All screens in your app that are not the main entrance to your app (the "home" screen)
+should offer the user a way to navigate to the logical parent screen in the app's hierarchy by
+pressing the <em>Up</em> button in the <a
+href="{@docRoot}guide/topics/ui/actionbar.html">action bar</a>.
+This lesson shows you how to properly implement this behavior.</p>
+
+<div class="note design">
+<p><strong>Up Navigation Design</strong></p>
+<p>The concepts and principles for <em>Up</em> navigation are described in <a
+href="{@docRoot}training/design-navigation/ancestral-temporal.html">Designing Effective
+Navigation</a> and the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design
+guide.</p>
+</div>
-<h2 id="up">Implement <em>Up</em> Navigation</h2>
+<img src="{@docRoot}images/training/implementing-navigation-up.png" id="figure-up">
+<p class="img-caption"><strong>Figure 1.</strong> The <em>Up</em> button in the action bar.</p>
-<p>When implementing ancestral navigation, all screens in your application that aren't the home screen should offer a means of navigating to the immediate parent screen in the hierarchy via the <em>Up</em> button in the action bar.</p>
-<img src="{@docRoot}images/training/implementing-navigation-up.png"
- alt="The Up button in the action bar." id="figure-up">
+<h2 id="SpecifyParent">Specify the Parent Activity</h2>
-<p class="img-caption"><strong>Figure 1.</strong> The <em>Up</em> button in the action bar.</p>
+<p>To implement <em>Up</em> navigation, the first step is to declare which activity is the
+appropriate parent for each activity. Doing so allows the system to facilitate navigation patterns
+such as <em>Up</em> because the system can determine the logical parent activity from
+the manifest file.</p>
+
+<p>Beginning in Android 4.1 (API level 16), you can declare the logical parent of each
+activity by specifying the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
+android:parentActivityName}</a> attribute
+in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code <activity>}</a>
+element.</p>
+
+<p>If your app supports Android 4.0 and lower, include the
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> with your app and
+add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+<activity>}</a>. Then specify the parent activity as the value
+for {@code android.support.PARENT_ACTIVITY}, matching the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
+android:parentActivityName}</a> attribute.</p>
+
+<p>For example:</p>
-<p>Regardless of how the current screen was reached, pressing this button should always take the user to the same screen in the hierarchy.</p>
+<pre>
+<application ... >
+ ...
+ <!-- The main/home activity (it has no parent activity) -->
+ <activity
+ android:name="com.example.myfirstapp.MainActivity" ...>
+ ...
+ </activity>
+ <!-- A child of the main activity -->
+ <activity
+ android:name="com.example.myfirstapp.DisplayMessageActivity"
+ android:label="@string/title_activity_display_message"
+ android:parentActivityName="com.example.myfirstapp.MainActivity" >
+ <!-- Parent activity meta-data to support 4.0 and lower -->
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="com.example.myfirstapp.MainActivity" />
+ </activity>
+</application>
+</pre>
+
+<p>With the parent activity declared this way, you can navigate <em>Up</em>
+to the appropriate parent using the {@link android.support.v4.app.NavUtils} APIs, as shown in
+the following sections.</p>
-<p>To implement <em>Up</em>, enable it in the action bar in your activity's {@link android.app.Activity#onCreate onCreate()} method:</p>
+
+<h2 id="up">Add Up Action</h2>
+
+<p>To allow <em>Up</em> navigation with the app icon in the action bar, call
+{@link android.app.ActionBar#setDisplayHomeAsUpEnabled setDisplayHomeAsUpEnabled()}:</p>
<pre>
{@literal @}Override
public void onCreate(Bundle savedInstanceState) {
...
getActionBar().setDisplayHomeAsUpEnabled(true);
- ...
}
</pre>
-<p>You should also handle <code>android.R.id.home</code> in {@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()}. This resource is the menu item ID for the <em>Home</em> (or <em>Up</em>) button. To ensure that a specific parent activity is shown, <em>DO NOT</em> simply call {@link android.app.Activity#finish finish()}. Instead, use an intent such as the one described below.</p>
+<p>This adds a left-facing caret alongside the app icon and enables it as an action button
+such that when the user presses it, your activity receives a call to
+{@link android.app.Activity#onOptionsItemSelected onOptionsItemSelected()}. The
+ID for the action is {@code android.R.id.home}.</p>
+
+
+
+<h2 id="NavigateUp">Navigate Up to Parent Activity</h2>
+
+<p>To navigate up when the user presses the app icon, you can use the {@link
+android.support.v4.app.NavUtils} class's static method,
+{@link android.support.v4.app.NavUtils#navigateUpFromSameTask
+navigateUpFromSameTask()}. When you call this method, it finishes the current activity and
+starts (or resumes) the appropriate parent activity.
+If the target parent activity is in the task's back stack, it is brought
+forward as defined by {@link android.content.Intent#FLAG_ACTIVITY_CLEAR_TOP}.</p>
+
+<p>For example:</p>
<pre>
{@literal @}Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- // This is called when the Home (Up) button is pressed
- // in the Action Bar.
- Intent parentActivityIntent = new Intent(this, MyParentActivity.class);
- parentActivityIntent.addFlags(
- Intent.FLAG_ACTIVITY_CLEAR_TOP |
- Intent.FLAG_ACTIVITY_NEW_TASK);
- startActivity(parentActivityIntent);
- finish();
- return true;
+ // Respond to the action bar's Up/Home button
+ case android.R.id.home:
+ NavUtils.navigateUpFromSameTask(this);
+ return true;
}
return super.onOptionsItemSelected(item);
}
</pre>
-<p>When the current activity belongs to a task from a different application—for example if it was reached via an intent from another application—pressing <em>Up</em> should create a new task for the application with a synthesized back stack. This approach is described in <a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a> and the {@link android.support.v4.app.TaskStackBuilder} class reference.</p>
+<p>However, using {@link android.support.v4.app.NavUtils#navigateUpFromSameTask
+navigateUpFromSameTask()} is suitable <strong>only when your app is the owner of the current
+task</strong> (that is, the user began this task from your app). If that's not true and your
+activity was started in a task that belongs to a different app, then
+navigating <em>Up</em> should create a new task that belongs to your app, which
+requires that you create a new back stack.</p>
+
+
+<h3 id="BuildBackStack">Navigate up with a new back stack</h3>
-<p>The {@link android.support.v4.app.NavUtils} and {@link android.support.v4.app.TaskStackBuilder} classes in the <a href="{@docRoot}tools/extras/support-library.html">Android Support Package</a> provide helpers for implementing this behavior correctly. An example usage of these two helper classes is below:</p>
+<p>If your activity provides any <a
+href="{@docRoot}guide/components/intents-filters.html#ifs">intent filters</a>
+that allow other apps to start the
+activity, you should implement the {@link android.app.Activity#onOptionsItemSelected
+onOptionsItemSelected()} callback such that if the user presses the <em>Up</em> button
+after entering your activity from another app's task, your app starts a new task
+with the appropriate back stack before navigating up.</p>
+
+<p>You can do so by first calling
+{@link android.support.v4.app.NavUtils#shouldUpRecreateTask shouldUpRecreateTask()} to check
+whether the current activity instance exists in a different app's task. If
+it returns true, then build a new task with {@link android.support.v4.app.TaskStackBuilder}.
+Otherwise, you can use the {@link android.support.v4.app.NavUtils#navigateUpFromSameTask
+navigateUpFromSameTask()} method as shown above.</p>
+
+<p>For example:</p>
<pre>
{@literal @}Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- case android.R.id.home:
- Intent upIntent = new Intent(this, MyParentActivity.class);
- if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
- // This activity is not part of the application's task, so create a new task
- // with a synthesized back stack.
- TaskStackBuilder.from(this)
- .addNextIntent(new Intent(this, MyGreatGrandParentActivity.class))
- .addNextIntent(new Intent(this, MyGrandParentActivity.class))
- .addNextIntent(upIntent)
- .startActivities();
- finish();
- } else {
- // This activity is part of the application's task, so simply
- // navigate up to the hierarchical parent activity.
- NavUtils.navigateUpTo(this, upIntent);
- }
- return true;
+ // Respond to the action bar's Up/Home button
+ case android.R.id.home:
+ Intent upIntent = NavUtils.getParentActivityIntent(this);
+ if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
+ // This activity is NOT part of this app's task, so create a new task
+ // when navigating up, with a synthesized back stack.
+ TaskStackBuilder.create(this)
+ // Add all of this activity's parents to the back stack
+ .addNextIntentWithParentStack(upIntent)
+ // Navigate up to the closest parent
+ .startActivities();
+ } else {
+ // This activity is part of this app's task, so simply
+ // navigate up to the logical parent activity.
+ NavUtils.navigateUpTo(this, upIntent);
+ }
+ return true;
}
return super.onOptionsItemSelected(item);
}
</pre>
-<h2 id="app-home">Properly Handle the Application Home Screen</h2>
-
-<p>By default, the <em>Home</em> button in the action bar is interactive. Since it does not make much sense to navigate home—or up one level—while on the home screen, you should disable the button like so:</p>
-
-<pre>
-getActionBar().setHomeButtonEnabled(false);
-</pre>
+<p class="note"><strong>Note:</strong> In order for the {@link
+android.support.v4.app.TaskStackBuilder#addNextIntentWithParentStack addNextIntentWithParentStack()}
+method to work,
+you must declare the logical parent of each activity in your manifest file, using the
+<a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
+android:parentActivityName}</a> attribute (and corresponding <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a> element)
+as described above.</p>
page.title=Implementing Effective Navigation
-page.tags="viewpager","tasks","back","up"
+page.tags="viewpager","tasks","back","up","swipe view","drawer"
trainingnavtop=true
startpage=true
<h2>Dependencies and prerequisites</h2>
<ul>
- <li>API level 14</li>
+ <li>Android 2.2 or higher</li>
<li>Understanding of fragments and Android layouts</li>
- <li><a href="{@docRoot}tools/extras/support-library.html">The Android Support Package</a></li>
+ <li><a href="{@docRoot}tools/extras/support-library.html">Android Support Library</a></li>
<li><a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a></li>
</ul>
<p>This class demonstrates how to implement the key navigation design patterns detailed in the
<a href="{@docRoot}training/design-navigation/index.html">Designing Effective Navigation</a> class.
-The lessons in this class cover implementing navigation up, down, and across your application's <a
-href="{@docRoot}training/design-navigation/screen-planning.html#diagram- relationships">screen
-map</a>.</p>
+</p>
-<p>After reading through the lessons in this class and exploring the associated sample application
-(see right), you should also have a basic understanding of how to use
-{@link android.app.ActionBar} and {@link android.support.v4.view.ViewPager}, two components that are fundamental to core app navigation.</p>
+<p>After reading the lessons in this class, you should have a strong understanding of how to
+implement navigation patterns with tabs, swipe views, and a navigation drawer. You should also
+understand how to provide proper <em>Up</em> and <em>Back</em> navigation.</p>
+<p class="note"><strong>Note:</strong> Several elements of this class require the
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> APIs.
+If you have not used the Support Library before, follow the lesson about <a
+href="{@docRoot}training/basics/fragments/support-lib.html">Using the Support Library</a>
+to get your project set up.</p>
-<h2 id="lessons">Lessons</h2>
+<h2 id="lessons">Lessons</h2>
<dl>
- <dt><strong><a href="lateral.html">Implementing Lateral Navigation</a></strong></dt>
- <dd>Learn how to implement tabs and horizontal paging (swipe views).</dd>
+ <dt><strong><a href="lateral.html">Creating Swipe Views with Tabs</a></strong></dt>
+ <dd>Learn how to implement tabs in the action bar and provide
+ horizontal paging (swipe views) to navigate between tabs.</dd>
+
+ <dt><strong><a href="nav-drawer.html">Creating a Navigation Drawer</a></strong></dt>
+ <dd>Learn how to build an interface with a hidden navigation drawer on the side
+ of the screen that opens with a swipe or by pressing the action bar's app icon.</dd>
- <dt><strong><a href="ancestral.html">Implementing Ancestral Navigation</a></strong></dt>
- <dd>Learn how to implement <em>Up</em> navigation.</dd>
+ <dt><strong><a href="ancestral.html">Providing Up Navigation</a></strong></dt>
+ <dd>Learn how to implement <em>Up</em> navigation using the action bar's app icon.</dd>
- <dt><strong><a href="temporal.html">Implementing Temporal Navigation</a></strong></dt>
- <dd>Learn how to correctly handle the <em>Back</em> button.</dd>
+ <dt><strong><a href="temporal.html">Providing Proper Back Navigation</a></strong></dt>
+ <dd>Learn how to correctly handle the <em>Back</em> button in special cases,
+ including how to insert activities into the back stack when deep-linking the user
+ from notifications or app widgets.</dd>
<dt><strong><a href="descendant.html">Implementing Descendant Navigation</a></strong></dt>
- <dd>Learn the finer points of implementing navigation into your application's information hierarchy.</dd>
+ <dd>Learn the finer points of navigating down into your application's information hierarchy.</dd>
</dl>
-page.title=Implementing Lateral Navigation
-parent.title=Implementing Effective Navigation
-parent.link=index.html
+page.title=Creating Swipe Views with Tabs
trainingnavtop=true
-next.title=Implementing Ancestral Navigation
-next.link=ancestral.html
@jd:body
<h2>This lesson teaches you to</h2>
<ol>
- <li><a href="#tabs">Implement Tabs</a></li>
- <li><a href="#horizontal-paging">Implement Horizontal Paging (Swipe Views)</a></li>
- <li><a href="#swipe-tabs">Implement Swiping Between Tabs</a></li>
+ <li><a href="#horizontal-paging">Implement Swipe Views</a></li>
+ <li><a href="#tabs">Add Tabs to the Action Bar</a></li>
+ <li><a href="#swipe-tabs">Change Tabs with Swipe Views</a></li>
+ <li><a href="#PagerTitleStrip">Use a Title Strip Instead of Tabs</a></li>
</ol>
+
<h2>You should also read</h2>
<ul>
<li><a href="{@docRoot}training/design-navigation/descendant-lateral.html">Providing Descendant and Lateral Navigation</a></li>
</div>
-<p><em>Lateral navigation</em> is navigation between sibling screens in the application's screen hierarchy (sometimes referred to as a screen map). The most prominent lateral navigation patterns are tabs and horizontal paging (also known as swipe views). This pattern and others are described in <a href="{@docRoot}training/design-navigation/descendant-lateral.html">Designing Effective Navigation</a>. This lesson covers how to implement several of the primary lateral navigation patterns in Android.</p>
+<p>Swipe views provide lateral navigation between sibling screens such as tabs with
+a horizontal finger gesture (a pattern sometimes known as horizontal paging). This lesson teaches
+you how to create a tab layout with swipe views for switching between tabs, or how to show
+a title strip instead of tabs.</p>
-<h2 id="tabs">Implement Tabs</h2>
+<div class="note design">
+<p><strong>Swipe View Design</strong></p>
+<p>Before implementing these features, you should understand the concepts and recommendations
+as described in <a href="{@docRoot}training/design-navigation/descendant-lateral.html">Designing
+Effective Navigation</a> and the <a href="{@docRoot}design/patterns/swipe-views.html">Swipe
+Views</a> design guide.</p>
+</div>
-<p>Tabs allow the user to navigate between sibling screens by selecting the appropriate tab indicator available at the top of the display. In Android 3.0 and later, tabs are implemented using the {@link android.app.ActionBar} class, and are generally set up in {@link android.app.Activity#onCreate Activity.onCreate()}. In some cases, such as when horizontal space is limited and/or the number of tabs is large, an appropriate alternate presentation for tabs is a dropdown list (sometimes implemented using a {@link android.widget.Spinner}).</p>
-<p>In previous versions of Android, tabs could be implemented using a
-{@link android.widget.TabWidget} and {@link android.widget.TabHost}.</p>
-<p>As of Android 3.0, however, you should use either {@link android.app.ActionBar#NAVIGATION_MODE_TABS} or {@link android.app.ActionBar#NAVIGATION_MODE_LIST} along with the {@link android.app.ActionBar} class.</p>
-<h3>Implement the Tabs Pattern with NAVIGATION_MODE_TABS</h3>
-<p>To create tabs, you can use the following code in your activity's {@link android.app.Activity#onCreate onCreate()} method. Note that the exact presentation of tabs may vary per device and by the current device configuration, to make best use of available screen space. For example, Android may automatically collapse tabs into a dropdown list if tabs don't fit horizontally in the action bar.</p>
+<h2 id="horizontal-paging">Implement Swipe Views</h2>
-<pre>
-{@literal @}Override
-public void onCreate(Bundle savedInstanceState) {
- ...
- final ActionBar actionBar = getActionBar();
+<p>You can create swipe views in your app using the {@link android.support.v4.view.ViewPager}
+widget, available in the
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a>. The
+{@link android.support.v4.view.ViewPager} is a layout widget in which each child view is
+a separate page (a separate tab) in the layout.</p>
- // Specify that tabs should be displayed in the action bar.
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-
- // Create a tab listener that is called when the user changes tabs.
- ActionBar.TabListener tabListener = new ActionBar.TabListener() {
- public void onTabSelected(ActionBar.Tab tab,
- FragmentTransaction ft) { }
-
- public void onTabUnselected(ActionBar.Tab tab,
- FragmentTransaction ft) { }
-
- public void onTabReselected(ActionBar.Tab tab,
- FragmentTransaction ft) { }
- };
-
- // Add 3 tabs.
- for (int i = 0; i < 3; i++) {
- actionBar.addTab(
- actionBar.newTab()
- .setText("Tab " + (i + 1))
- .setTabListener(tabListener));
- }
- ...
-}
-</pre>
-
-<h3>Implement the Tabs Pattern with NAVIGATION_MODE_LIST</h3>
-
-<p>To use a dropdown list instead, use the following code in your activity's {@link android.app.Activity#onCreate onCreate()} method. Dropdown lists are often preferable in cases where more information must be shown per navigation item, such as unread message counts, or where the number of available navigation items is large.</p>
+<p>To set up your layout with {@link android.support.v4.view.ViewPager}, add a
+{@code <ViewPager>} element to your XML layout. For example, if each page in the swipe view
+should consume the entire layout, then your layout looks like this:</p>
<pre>
-{@literal @}Override
-public void onCreate(Bundle savedInstanceState) {
- ...
- final ActionBar actionBar = getActionBar();
-
- // Specify that a dropdown list should be displayed in the action bar.
- actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
-
- actionBar.setListNavigationCallbacks(
- // Specify a SpinnerAdapter to populate the dropdown list.
- new ArrayAdapter<String>(
- actionBar.getThemedContext(),
- android.R.layout.simple_list_item_1,
- android.R.id.text1,
- new String[]{ "Tab 1", "Tab 2", "Tab 3" }),
-
- // Provide a listener to be called when an item is selected.
- new ActionBar.OnNavigationListener() {
- public boolean onNavigationItemSelected(
- int position, long id) {
- // Take action here, e.g. switching to the
- // corresponding fragment.
- return true;
- }
- });
- ...
-}
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
</pre>
-<h2 id="horizontal-paging">Implement Horizontal Paging (Swipe Views)</h2>
+<p>To insert child views that represent each page,
+you need to hook this layout to a {@link android.support.v4.view.PagerAdapter}.
+There are two kinds of adapter you can use:</p>
-<p>Horizontal paging, or swipe views, allow users to <a href="{@docRoot}design/patterns/swipe-views.html">swipe</a> horizontally on the current screen to navigate to adjacent screens. This pattern can be implemented using the {@link android.support.v4.view.ViewPager} widget, currently available as part of the <a href="{@docRoot}tools/extras/support-library.html">Android Support Package</a>. For navigating between sibling screens representing a fixed number of sections, it's best to provide the {@link android.support.v4.view.ViewPager} with a {@link android.support.v4.app.FragmentPagerAdapter}. For horizontal paging across collections of objects, it's best to use a {@link android.support.v4.app.FragmentStatePagerAdapter}, which destroys fragments as the user navigates to other pages, minimizing memory usage.</p>
+<dl>
+ <dt>{@link android.support.v4.app.FragmentPagerAdapter}</dt>
+ <dd>This is best when navigating between sibling screens representing a fixed, small
+ number of pages.</dd>
+ <dt>{@link android.support.v4.app.FragmentStatePagerAdapter}</dt>
+ <dd>This is best for paging across a collection of objects
+for which the number of pages is undetermined. It destroys
+fragments as the user navigates to other pages, minimizing memory usage.</dd>
+</dl>
-<p>Below is an example of using a {@link android.support.v4.view.ViewPager} to swipe across a collection of objects.</p>
+<p>For example, here's how you might use {@link android.support.v4.app.FragmentStatePagerAdapter}
+to swipe across a collection of {@link android.app.Fragment} objects:</p>
<pre>
public class CollectionDemoActivity extends FragmentActivity {
// Since this is an object collection, use a FragmentStatePagerAdapter,
// and NOT a FragmentPagerAdapter.
-public class DemoCollectionPagerAdapter extends
- FragmentStatePagerAdapter {
+public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
public DemoCollectionPagerAdapter(FragmentManager fm) {
super(fm);
}
}
</pre>
-<p>You can also add indicators to your horizontal paging UI by adding a {@link android.support.v4.view.PagerTitleStrip}. Below is an example layout XML file for an activity whose entire contents are a {@link android.support.v4.view.ViewPager} and a top-aligned {@link android.support.v4.view.PagerTitleStrip} inside it. Individual pages (provided by the adapter) occupy the remaining space inside the {@link android.support.v4.view.ViewPager}.</p>
+<p>This example shows only the code necessary to create the swipe views. The following
+sections show how you can add tabs to help facilitate navigation between pages.</p>
+
+
+<h2 id="tabs">Add Tabs to the Action Bar</h2>
+
+<p>Action bar
+<a href="{@docRoot}design/building-blocks/tabs.html">tabs</a> offer users a familiar interface
+for navigating between and identifying sibling screens in your app.</p>
+
+<p>To create tabs using {@link android.app.ActionBar}, you need to enable
+{@link android.app.ActionBar#NAVIGATION_MODE_TABS}, then create several instances of
+{@link android.app.ActionBar.Tab} and supply an implementation of
+the {@link android.app.ActionBar.TabListener} interface for each one.
+For example, in your activity's {@link
+android.app.Activity#onCreate onCreate()} method, you can use code similar to this:</p>
<pre>
-<android.support.v4.view.ViewPager
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+ final ActionBar actionBar = getActionBar();
+ ...
- <android.support.v4.view.PagerTitleStrip
- android:id="@+id/pager_title_strip"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="top"
- android:background="#33b5e5"
- android:textColor="#fff"
- android:paddingTop="4dp"
- android:paddingBottom="4dp" />
+ // Specify that tabs should be displayed in the action bar.
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
-</android.support.v4.view.ViewPager>
+ // Create a tab listener that is called when the user changes tabs.
+ ActionBar.TabListener tabListener = new ActionBar.TabListener() {
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
+ // show the given tab
+ }
+
+ public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ // hide the given tab
+ }
+
+ public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {
+ // probably ignore this event
+ }
+ };
+
+ // Add 3 tabs, specifying the tab's text and TabListener
+ for (int i = 0; i < 3; i++) {
+ actionBar.addTab(
+ actionBar.newTab()
+ .setText("Tab " + (i + 1))
+ .setTabListener(tabListener));
+ }
+}
</pre>
-<h2 id="swipe-tabs">Implement Swiping Between Tabs</h2>
+<p>How you handle the {@link android.app.ActionBar.TabListener} callbacks to change tabs
+depends on how you've constructed your content. But if you're using fragments for each tab with
+{@link android.support.v4.view.ViewPager} as shown above, the following
+section shows how to switch between pages when the user selects a tab and also update the selected
+tab when the user swipes between pages.</p>
+
+
+<h2 id="swipe-tabs">Change Tabs with Swipe Views</h2>
-<p>One of the key design recommendations in Android 4.0 for tabs is to <a href="{@docRoot}design/patterns/swipe-views.html">allow swiping</a> between them where appropriate. This behavior enables users to swipe horizontally across the selected tab's contents to navigate to adjacent tabs, without needed to directly interact with the tabs themselves. To implement this, you can use a {@link android.support.v4.view.ViewPager} in conjunction with the {@link android.app.ActionBar} tabs API.</p>
+<p>To switch between pages in a {@link android.support.v4.view.ViewPager} when the user selects
+a tab, implement your {@link android.app.ActionBar.TabListener} to select the appropriate page
+by calling {@link android.support.v4.view.ViewPager#setCurrentItem setCurrentItem()} on your
+{@link android.support.v4.view.ViewPager}:</p>
+
+<pre>
+{@literal @}Override
+public void onCreate(Bundle savedInstanceState) {
+ ...
+
+ // Create a tab listener that is called when the user changes tabs.
+ ActionBar.TabListener tabListener = new ActionBar.TabListener() {
+ public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
+ // When the tab is selected, switch to the
+ // corresponding page in the ViewPager.
+ mViewPager.setCurrentItem(tab.getPosition());
+ }
+ ...
+ };
+}
+</pre>
-<p>Upon observing the current page changing, select the corresponding tab. You can set up this behavior using an {@link android.support.v4.view.ViewPager.OnPageChangeListener} in your activity's {@link android.app.Activity#onCreate onCreate()} method:</p>
+<p>Likewise, you should select the corresponding tab when the user swipes between pages with a
+touch gesture. You can set up this behavior by implementing the
+{@link android.support.v4.view.ViewPager.OnPageChangeListener} interface to change
+the current tab each time the page changes. For example:</p>
<pre>
{@literal @}Override
public void onCreate(Bundle savedInstanceState) {
...
+
+ mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setOnPageChangeListener(
new ViewPager.SimpleOnPageChangeListener() {
{@literal @}Override
}
</pre>
-<p>And upon selecting a tab, switch to the corresponding page in the {@link android.support.v4.view.ViewPager}. To do this, add an {@link android.app.ActionBar.TabListener} to your tab when creating it using the {@link android.app.ActionBar#newTab newTab()} method:</p>
+
+
+<h2 id="PagerTitleStrip">Use a Title Strip Instead of Tabs</h2>
+
+<p>If you don't want to include action bar tabs and prefer to provide
+<a href="{@docRoot}design/building-blocks/tabs.html#scrollable">scrollable tabs</a> for a shorter
+visual profile, you can use {@link android.support.v4.view.PagerTitleStrip} with
+your swipe views.</p>
+
+<p>Below is an example layout XML file for an
+activity whose entire contents are a {@link android.support.v4.view.ViewPager} and a top-aligned
+{@link android.support.v4.view.PagerTitleStrip} inside it. Individual pages (provided by the
+adapter) occupy the remaining space inside the {@link android.support.v4.view.ViewPager}.</p>
<pre>
-actionBar.newTab()
- ...
- .setTabListener(new ActionBar.TabListener() {
- public void onTabSelected(ActionBar.Tab tab,
- FragmentTransaction ft) {
- // When the tab is selected, switch to the
- // corresponding page in the ViewPager.
- mViewPager.setCurrentItem(tab.getPosition());
- }
- ...
- }));
-</pre>
+<android.support.v4.view.ViewPager
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <android.support.v4.view.PagerTitleStrip
+ android:id="@+id/pager_title_strip"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top"
+ android:background="#33b5e5"
+ android:textColor="#fff"
+ android:paddingTop="4dp"
+ android:paddingBottom="4dp" />
+
+</android.support.v4.view.ViewPager>
+</pre>
\ No newline at end of file
--- /dev/null
+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
-page.title=Implementing Temporal Navigation
-parent.title=Implementing Effective Navigation
-parent.link=index.html
+page.title=Providing Proper Back Navigation
trainingnavtop=true
-previous.title=Implementing Ancestral Navigation
-previous.link=ancestral.html
-next.title=Implementing Descendant Navigation
-next.link=descendant.html
@jd:body
<h2>This lesson teaches you to:</h2>
<ol>
- <li><a href="#back-fragments">Implement <em>Back</em> Navigation with Fragments</a></li>
- <li><a href="#back-webviews">Implement <em>Back</em> Navigation with WebViews</a></li>
+ <li><a href="#SynthesizeBackStack">Synthesize a new Back Stack for Deep Links</a></li>
+ <li><a href="#back-fragments">Implement Back Navigation for Fragments</a></li>
+ <li><a href="#back-webviews">Implement Back Navigation for WebViews</a></li>
</ol>
<h2>You should also read</h2>
</div>
-<p><em>Temporal navigation</em> is navigation to previously visited screens. Users can visit previous screens by pressing the device <em>Back</em> button. This user interface pattern is described further in <a href="{@docRoot}training/design-navigation/ancestral-temporal.html">Providing Ancestral and Temporal Navigation</a> in <em>Designing Effective Navigation</em> and in <a href="{@docRoot}design/patterns/navigation.html">Android Design: Navigation</a>.</p>
+<p><em>Back</em> navigation is how users move backward through the history of screens
+they previously visited. All Android devices provide a <em>Back</em> button for this
+type of navigation, so <strong>your app should not add a Back button to the UI</strong>.</p>
-<p>Android handles basic <em>Back</em> navigation for you (see <a href="{@docRoot}guide/components/tasks-and-back-stack.html">Tasks and Back Stack</a> for details on this behavior). This lesson discusses a number of cases where applications should provide specialized logic for the <em>Back</em> button.</p>
+<p>In almost all situations, the system maintains a back stack of activities while the user
+navigates your application. This allows the system to properly navigate backward when the user
+presses the <em>Back</em> button. However, there are a few cases in which your app should manually
+specify the <em>Back</em> behavior in order to provide the best user experience.</p>
+<div class="note design">
+<p><strong>Back Navigation Design</strong></p>
+<p>Before continuing with this document, you should understand the
+concepts and principles for <em>Back</em> navigation as described in
+the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design
+guide.</p>
+</div>
+
+<p>Navigation patterns that require you to manually specify the <em>Back</em> behavior include:</p>
+<ul>
+ <li>When the user enters a deep-level activity directly from a <a
+ href="{@docRoot}guide/topics/ui/notifiers/notifications.html">notification</a>, an <a
+ href="{@docRoot}guide/topics/appwidgets/index.html">app widget</a>, or the <a
+ href="{@docRoot}training/implementing-navigation/nav-drawer.html">navigation drawer</a>.</li>
+ <li>Certain cases in which the user navigates between <a
+ href="{@docRoot}guide/components/fragments.html">fragments</a>.</li>
+ <li>When the user navigates web pages in a {@link android.webkit.WebView}.</li>
+</ul>
+
+<p>How to implement proper <em>Back</em> navigation in these situations is described
+in the following sections.</p>
+
+
+
+<h2 id="SynthesizeBackStack">Synthesize a new Back Stack for Deep Links</h2>
+
+<p>Ordinarily, the system incrementally builds the back stack as the user navigates from one
+activity to the next. However, when the user enters your app with a <em>deep link</em> that
+starts the activity in its own task, it's necessary for you to synthesize a new
+back stack because the activity is running in a new task without any back stack at all.</p>
+
+<p>For example, when a notification takes the user to an activity deep in your app hierarchy,
+you should add activities into your task's back stack so that pressing <em>Back</em> navigates
+up the app hierarchy instead of exiting the app. This pattern is described further in the
+<a href="{@docRoot}design/patterns/navigation.html#into-your-app"
+>Navigation</a> design guide.</p>
+
+
+<h3 id="SpecifyParent">Specify parent activities in the manifest</h3>
+
+<p>Beginning in Android 4.1 (API level 16), you can declare the logical parent of each
+activity by specifying the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
+android:parentActivityName}</a> attribute
+in the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+<activity>}</a> element. This allows the system to facilitate navigation patterns
+because it can determine the logical <em>Back</em> or <em>Up</em> navigation path with this
+information.</p>
+
+<p>If your app supports Android 4.0 and lower, include the
+<a href="{@docRoot}tools/extras/support-library.html">Support Library</a> with your app and
+add a <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a>
+element inside the <a href="{@docRoot}guide/topics/manifest/activity-element.html">{@code
+<activity>}</a>. Then specify the parent activity as the value
+for {@code android.support.PARENT_ACTIVITY}, matching the <a
+href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
+android:parentActivityName}</a> attribute.</p>
+
+<p>For example:</p>
+
+<pre>
+<application ... >
+ ...
+ <!-- The main/home activity (it has no parent activity) -->
+ <activity
+ android:name="com.example.myfirstapp.MainActivity" ...>
+ ...
+ </activity>
+ <!-- A child of the main activity -->
+ <activity
+ android:name="com.example.myfirstapp.DisplayMessageActivity"
+ android:label="@string/title_activity_display_message"
+ android:parentActivityName="com.example.myfirstapp.MainActivity" >
+ <!-- The meta-data element is needed for versions lower than 4.1 -->
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="com.example.myfirstapp.MainActivity" />
+ </activity>
+</application>
+</pre>
+
+<p>With the parent activity declared this way, you can use the
+{@link android.support.v4.app.NavUtils} APIs to synthesize a new back stack by identifying which
+activity is the appropriate parent for each activity.</p>
-<h2 id="back-fragments">Implement <em>Back</em> Navigation with Fragments</h2>
-<p>When using fragments in your application, individual {@link android.app.FragmentTransaction} objects can represent context changes that should be added to the back stack. For example, if you are implementing a <a href="descendant.html#master-detail">master/detail flow</a> on a handset by swapping out fragments (thus emulating a {@link android.app.Activity#startActivity startActivity()} call), you should ensure that pressing the <em>Back</em> button on a detail screen returns the user to the master screen. To do so, you can use {@link android.app.FragmentTransaction#addToBackStack addToBackStack()}:</p>
+
+<h3 id="CreateBackStack">Create back stack when starting the activity</h3>
+
+<p>Adding activities to the back stack begins upon the event that takes the user into your app.
+That is, instead of calling {@link android.content.Context#startActivity startActivity()}, use the
+{@link android.support.v4.app.TaskStackBuilder} APIs to define each activity that should
+be placed into a new back stack. Then begin the target activity by calling {@link
+android.support.v4.app.TaskStackBuilder#startActivities startActivities()}, or create the
+appropriate {@link android.app.PendingIntent} by calling {@link
+android.support.v4.app.TaskStackBuilder#getPendingIntent getPendingIntent()}.</p>
+
+<p>For example, when a notification takes the user to an activity deep in your app hierarchy,
+you can use this code to create a {@link android.app.PendingIntent}
+that starts an activity and inserts a new back stack into the target task:</p>
+
+<pre>
+// Intent for the activity to open when user selects the notification
+Intent detailsIntent = new Intent(this, DetailsActivity.class);
+
+// Use TaskStackBuilder to build the back stack and get the PendingIntent
+PendingIntent pendingIntent =
+ TaskStackBuilder.create(this)
+ // add all of DetailsActivity's parents to the stack,
+ // followed by DetailsActivity itself
+ .addNextIntentWithParentStack(upIntent)
+ .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
+
+NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
+builder.setContentIntent(pendingIntent);
+...
+</pre>
+
+<p>The resulting {@link android.app.PendingIntent} specifies not only the activity to
+start (as defined by {@code detailsIntent}), but also the back stack that should be inserted
+into the task (all parents of the {@code DetailsActivity} defined by {@code detailsIntent}).
+So when the {@code DetailsActivity} starts, pressing <em>Back</em>
+navigates backward through each of the {@code DetailsActivity} class's parent activities.</p>
+
+<p class="note"><strong>Note:</strong> In order for the {@link
+android.support.v4.app.TaskStackBuilder#addNextIntentWithParentStack addNextIntentWithParentStack()}
+method to work,
+you must declare the logical parent of each activity in your manifest file, using the
+<a href="{@docRoot}guide/topics/manifest/activity-element.html#parent">{@code
+android:parentActivityName}</a> attribute (and corresponding <a
+href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code <meta-data>}</a> element)
+as described above.</p>
+
+
+
+
+
+<h2 id="back-fragments">Implement Back Navigation for Fragments</h2>
+
+<p>When using fragments in your app, individual {@link android.app.FragmentTransaction}
+objects may represent context changes that should be added to the back stack. For example, if you
+are implementing a <a href="descendant.html#master-detail">master/detail flow</a> on a handset by
+swapping out fragments, you should ensure that pressing the <em>Back</em> button on a detail
+screen returns the user to the master screen. To do so, call {@link
+android.app.FragmentTransaction#addToBackStack addToBackStack()} before you commit
+the transaction:</p>
<pre>
// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
-getFragmentManager().beginTransaction()
- .add(detailFragment, "detail")
-
- // Add this transaction to the back stack and commit.
- .addToBackStack()
- .commit();
+getSupportFragmentManager().beginTransaction()
+ .add(detailFragment, "detail")
+ // Add this transaction to the back stack
+ .addToBackStack()
+ .commit();
</pre>
-<p>The activity's {@link android.app.FragmentManager} handles <em>Back</em> button presses if there are {@link android.app.FragmentTransaction} objects on the back stack. When this happens, the {@link android.app.FragmentManager} pops the most recent transaction off the back stack and performs the reverse action (e.g., removing a fragment if the transaction added it).</p>
+<p>When there are {@link android.app.FragmentTransaction} objects on the back stack and the user
+presses the <em>Back</em> button,
+the {@link android.app.FragmentManager} pops the most recent transaction off the back stack and
+performs the reverse action (such as removing a fragment if the transaction added it).</p>
-<p>If your application updates other user interface elements to reflect the current state of your fragments, such as the action bar, remember to update the UI when you commit the transaction. You should update your user interface after the fragment manager back stack changes in addition to when you commit the transaction. You can listen for when a <code>FragmentTransaction</code> is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</p>
+<p class="note"><strong>Note:</strong> You <strong>should not add transactions to the back
+stack</strong> when the transaction is for horizontal navigation (such as when switching tabs)
+or when modifying the content appearance (such as when adjusting filters). For more information,
+about when <em>Back</em> navigation is appropriate,
+see the <a href="{@docRoot}design/patterns/navigation.html">Navigation</a> design guide.</p>
+
+<p>If your application updates other user interface elements to reflect the current state of your
+fragments, such as the action bar, remember to update the UI when you commit the transaction. You
+should update your user interface after the back stack changes in addition to
+when you commit the transaction. You can listen for when a {@link android.app.FragmentTransaction}
+is reverted by setting up an {@link android.app.FragmentManager.OnBackStackChangedListener}:</p>
<pre>
-getFragmentManager().addOnBackStackChangedListener(
+getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// Update your UI here.
});
</pre>
-<h2 id="back-webviews">Implement <em>Back</em> Navigation with WebViews</h2>
-<p>If a part of your application is contained in a {@link android.webkit.WebView}, it may be appropriate for <em>Back</em> to traverse browser history. To do so, you can override {@link android.app.Activity#onBackPressed onBackPressed()} and proxy to the <code>WebView</code> if it has history state:</p>
+
+<h2 id="back-webviews">Implement Back Navigation for WebViews</h2>
+
+<p>If a part of your application is contained in a {@link android.webkit.WebView}, it may be
+appropriate for <em>Back</em> to traverse browser history. To do so, you can override {@link
+android.app.Activity#onBackPressed onBackPressed()} and proxy to the
+{@link android.webkit.WebView} if it has history state:</p>
<pre>
{@literal @}Override
}
</pre>
-<p>Be careful when using this mechanism with highly dynamic web pages that can grow a large history. Pages that generate an extensive history, such as those that make frequent changes to the document hash, may make it tedious for users to get out of your activity.</p>
+<p>Be careful when using this mechanism with highly dynamic web pages that can grow a large
+history. Pages that generate an extensive history, such as those that make frequent changes to
+the document hash, may make it tedious for users to get out of your activity.</p>
+
+<p>For more information about using {@link android.webkit.WebView}, read <a
+href="{@docRoot}guide/webapps/webview.html">Building Web Apps in WebView</a>.
<div class="nav-section-header">
<a href="<?cs var:toroot ?>training/implementing-navigation/index.html"
description=
- "How to implement various navigation patterns such as swipe views and up navigation."
+ "How to implement various navigation patterns such as swipe views,
+ a navigation drawer, and up navigation."
>Implementing Effective Navigation</a>
</div>
<ul>
<li><a href="<?cs var:toroot ?>training/implementing-navigation/lateral.html">
- Implementing Lateral Navigation
+ Creating Swipe Views with Tabs
+ </a>
+ </li>
+ <li><a href="<?cs var:toroot ?>training/implementing-navigation/nav-drawer.html">
+ Creating a Navigation Drawer
</a>
</li>
<li><a href="<?cs var:toroot ?>training/implementing-navigation/ancestral.html">
- Implementing Ancestral Navigation
+ Providing Up Navigation
</a>
</li>
<li><a href="<?cs var:toroot ?>training/implementing-navigation/temporal.html">
- Implementing Temporal Navigation
+ Providing Proper Back Navigation
</a>
</li>
<li><a href="<?cs var:toroot ?>training/implementing-navigation/descendant.html">