cc0be914a9
Change-Id: Ic80228c1293811d85a8177c8800e7c68b84fee4e
302 lines
11 KiB
Plaintext
302 lines
11 KiB
Plaintext
page.title=Creating Swipe Views with Tabs
|
|
page.tags="viewpager","horizontal","paging","swipe view","tabs"
|
|
|
|
trainingnavtop=true
|
|
|
|
@jd:body
|
|
|
|
<div id="tb-wrapper">
|
|
<div id="tb">
|
|
|
|
<h2>This lesson teaches you to</h2>
|
|
<ol>
|
|
<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>
|
|
<li><a href="{@docRoot}design/building-blocks/tabs.html">Android Design: Tabs</a></li>
|
|
<li><a href="{@docRoot}design/patterns/swipe-views.html">Android Design: Swipe Views</a></li>
|
|
</ul>
|
|
|
|
<h2>Try it out</h2>
|
|
|
|
<div class="download-box">
|
|
<a href="http://developer.android.com/shareables/training/EffectiveNavigation.zip"
|
|
class="button">Download the sample app</a>
|
|
<p class="filename">EffectiveNavigation.zip</p>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<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>
|
|
|
|
<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>
|
|
|
|
|
|
|
|
|
|
|
|
<h2 id="horizontal-paging">Implement Swipe Views</h2>
|
|
|
|
<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/support-library/index.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>
|
|
|
|
<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>
|
|
<?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>
|
|
|
|
<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>
|
|
|
|
<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>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 {
|
|
// When requested, this adapter returns a DemoObjectFragment,
|
|
// representing an object in the collection.
|
|
DemoCollectionPagerAdapter mDemoCollectionPagerAdapter;
|
|
ViewPager mViewPager;
|
|
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
setContentView(R.layout.activity_collection_demo);
|
|
|
|
// ViewPager and its adapters use support library
|
|
// fragments, so use getSupportFragmentManager.
|
|
mDemoCollectionPagerAdapter =
|
|
new DemoCollectionPagerAdapter(
|
|
getSupportFragmentManager());
|
|
mViewPager = (ViewPager) findViewById(R.id.pager);
|
|
mViewPager.setAdapter(mDemoCollectionPagerAdapter);
|
|
}
|
|
}
|
|
|
|
// Since this is an object collection, use a FragmentStatePagerAdapter,
|
|
// and NOT a FragmentPagerAdapter.
|
|
public class DemoCollectionPagerAdapter extends FragmentStatePagerAdapter {
|
|
public DemoCollectionPagerAdapter(FragmentManager fm) {
|
|
super(fm);
|
|
}
|
|
|
|
{@literal @}Override
|
|
public Fragment getItem(int i) {
|
|
Fragment fragment = new DemoObjectFragment();
|
|
Bundle args = new Bundle();
|
|
// Our object is just an integer :-P
|
|
args.putInt(DemoObjectFragment.ARG_OBJECT, i + 1);
|
|
fragment.setArguments(args);
|
|
return fragment;
|
|
}
|
|
|
|
{@literal @}Override
|
|
public int getCount() {
|
|
return 100;
|
|
}
|
|
|
|
{@literal @}Override
|
|
public CharSequence getPageTitle(int position) {
|
|
return "OBJECT " + (position + 1);
|
|
}
|
|
}
|
|
|
|
// Instances of this class are fragments representing a single
|
|
// object in our collection.
|
|
public static class DemoObjectFragment extends Fragment {
|
|
public static final String ARG_OBJECT = "object";
|
|
|
|
{@literal @}Override
|
|
public View onCreateView(LayoutInflater inflater,
|
|
ViewGroup container, Bundle savedInstanceState) {
|
|
// The last two arguments ensure LayoutParams are inflated
|
|
// properly.
|
|
View rootView = inflater.inflate(
|
|
R.layout.fragment_collection_object, container, false);
|
|
Bundle args = getArguments();
|
|
((TextView) rootView.findViewById(android.R.id.text1)).setText(
|
|
Integer.toString(args.getInt(ARG_OBJECT)));
|
|
return rootView;
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<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>
|
|
{@literal @}Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
final ActionBar actionBar = getActionBar();
|
|
...
|
|
|
|
// 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) {
|
|
// 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>
|
|
|
|
<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>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>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
|
|
public void onPageSelected(int position) {
|
|
// When swiping between pages, select the
|
|
// corresponding tab.
|
|
getActionBar().setSelectedNavigationItem(position);
|
|
}
|
|
});
|
|
...
|
|
}
|
|
</pre>
|
|
|
|
|
|
|
|
<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>
|
|
<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>
|