page.title=Creating Swipe Views with Tabs page.tags=viewpager,horizontal,paging,swipe view,tabs trainingnavtop=true @jd:body
EffectiveNavigation.zip
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.
Swipe View Design
Before implementing these features, you should understand the concepts and recommendations as described in Designing Effective Navigation and the Swipe Views design guide.
You can create swipe views in your app using the {@link android.support.v4.view.ViewPager} widget, available in the Support Library. 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.
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:
<?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" />
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:
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:
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; } }
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.
Action bar tabs offer users a familiar interface for navigating between and identifying sibling screens in your app.
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:
{@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)); } }
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.
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}:
{@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()); } ... }; }
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:
{@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); } }); ... }
If you don't want to include action bar tabs and prefer to provide scrollable tabs for a shorter visual profile, you can use {@link android.support.v4.view.PagerTitleStrip} with your swipe views.
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}.
<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>