| page.title=Creating Swipe Views with Tabs |
| page.tags="viewpager","horizontal","paging","swipe view" |
| |
| 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> |