Android: Creando Swipe Views con Tabs

[Fuente : http://developer.android.com/training/implementing-navigation/lateral.html]

THIS LESSON TEACHES YOU TO

  1. Implement Swipe Views
  2. Add Tabs to the Action Bar
  3. Change Tabs with Swipe Views
  4. Use a Title Strip Instead of Tabs

YOU SHOULD ALSO READ

Las swipe views proporcionan navegación lateral entre pantallas hermanas tales como las tabs con un gesto del dedo horizontal (un patrón algunas veces conocido como paginación horizontal). Este post nos enseña cómo crear un Tab Layout con swipe views para poder moverse entre los tabs arrastrando el dedo.

Diseño de un Swipe View 

Before implementing these features, you should understand the concepts and recommendations as described in Designing Effective Navigation and the Swipe Views design guide.

Implementación de las Swipe Views

Puedes crear swipe views en tu app utilizando el widget ViewPager, incluido el la Support Library. El ViewPager es un widget de layout en el que cada View hijo es una página separada (una tab separada) en el layout.

Para configurar tu layout con ViewPager , añade un elemento <ViewPager> al xml de tu layout. Por ejemplo, si cada página en la swipe view rellena el layout entero, entonces tu layout parece como esto:

<?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" />

Para insertar vistas hijas que representan cada página, necesitas enganchar este layout a un PagerAdapter. Hay dos tipos de adaptadores que puedes utilizar:

FragmentPagerAdapter
Esto es mejor cuando navegando entre pantallas hermanas estas son un número fijo y pequeño de páginas.
FragmentStatePagerAdapter
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.

For example, here’s how you might use FragmentStatePagerAdapter to swipe across a collection of 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);
    }

    @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;
    }

    @Override
    public int getCount() {
        return 100;
    }

    @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";

    @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.

Add Tabs to the Action Bar


Action bar tabs offer users a familiar interface for navigating between and identifying sibling screens in your app.

To create tabs using ActionBar, you need to enable NAVIGATION_MODE_TABS, then create several instances ofActionBar.Tab and supply an implementation of the ActionBar.TabListener interface for each one. For example, in your activity’s onCreate() method, you can use code similar to this:

@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 ActionBar.TabListener callbacks to change tabs depends on how you’ve constructed your content. But if you’re using fragments for each tab with 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.

Change Tabs with Swipe Views


To switch between pages in a ViewPager when the user selects a tab, implement yourActionBar.TabListener to select the appropriate page by calling setCurrentItem() on your ViewPager:

@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 ViewPager.OnPageChangeListener interface to change the current tab each time the page changes. For example:

@Override
public void onCreate(Bundle savedInstanceState) {
    ...

    mViewPager = (ViewPager) findViewById(R.id.pager);
    mViewPager.setOnPageChangeListener(
            new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    // When swiping between pages, select the
                    // corresponding tab.
                    getActionBar().setSelectedNavigationItem(position);
                }
            });
    ...
}

Use a Title Strip Instead of Tabs


If you don’t want to include action bar tabs and prefer to provide scrollable tabs for a shorter visual profile, you can use PagerTitleStrip with your swipe views.

Below is an example layout XML file for an activity whose entire contents are a ViewPager and a top-alignedPagerTitleStrip inside it. Individual pages (provided by the adapter) occupy the remaining space inside theViewPager.

<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>