Tuesday, September 20, 2011

ViewPager meets Swipey Tabs

Revision 3 of the Android compatibility package brought us the awesome class ViewPager. The new Android Market app has these nice Swipey Tabs of which the bits and pieces are explained by Kirill Grouchnikov.

A sample swipey tabs application based on this ViewPager can be found at http://code.google.com/p/android-playground.


The main elements are the class SwipeyTabs and the interface SwipeyTabsAdapter.

Layout defintions

The first layout definition we need is the one that will host our SwipeyTabs along with the ViewPager.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:swipeytabs="http://schemas.android.com/apk/res/net.peterkuterna.android.apps.swipeytabs"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <net.peterkuterna.android.apps.swipeytabs.SwipeyTabs
        android:id="@+id/swipeytabs"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        swipeytabs:bottomBarColor="#ff96aa39"
        swipeytabs:bottomBarHeight="2dip"
        swipeytabs:tabIndicatorHeight="3dip"
        android:background="#ff3b3b3b"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="fill_parent"
        android:layout_height="0px"
        android:layout_weight="1" />

</LinearLayout>

As you can see, you can customize the layout of the swipey tab with the attributes bottomBarColor, bottomBarHeight and tabIndicatorHeight.

Second we will need a TextView layout definition that we are going to inflate when SwipeyTabs asks us to create a tab for a given position.
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/swipey_tab"
    android:layout_width="wrap_content"
    android:layout_height="30dip"
    android:paddingLeft="15dip"
    android:paddingRight="15dip"
    android:focusable="true"
    android:singleLine="true"
    android:textSize="14sp"
    android:background="@drawable/swipey_tab_indicator" />

As last we have a layout definition for the fragment we are going to instantiate in the FragmentPagerAdapter.
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <TextView 
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"/>
    
</FrameLayout>

Setting up the adapter

The adapter that we inject into the ViewPager and SwipeyTabs simply extends the FragmentPagerAdapter and implements the interface SwipeyTabsAdapter. As soon as you set the adapter on the swipey tabs object, it will ask your adapter to deliver a TextView for a given position. The implementation in the sample application is as follows:
public TextView getTab(final int position, SwipeyTabs root) {
    TextView view = (TextView) LayoutInflater.from(mContext).inflate(
        R.layout.swipey_tab_indicator, root, false);
    view.setText(TITLES[position]);
    view.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            mViewPager.setCurrentItem(position);
        }
    });
   
    return view;
}

Integration with the ViewPager

To integrate SwipeyTabs with the ViewPager you only need to inject the swipey tab object as an OnPageChangeListener in the ViewPager.
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_swipeytab);

    mViewPager = (ViewPager) findViewById(R.id.viewpager);
    mTabs = (SwipeyTabs) findViewById(R.id.swipeytabs);

    SwipeyTabsPagerAdapter adapter = new SwipeyTabsPagerAdapter(this, getSupportFragmentManager());
    mViewPager.setAdapter(adapter);
    mTabs.setAdapter(adapter);
    mViewPager.setOnPageChangeListener(mTabs);
    mViewPager.setCurrentItem(0);
}

7 comments:

  1. excellent! very useful tutorial

    ReplyDelete
  2. Thank you for your tutorial, i just wonder if there is a way to update the tab content when during run time?

    ReplyDelete
  3. Thanks! Have you noticed how the space between the focused tab and the tab to the left/right varies with the length of the tab titles? any way to fix this?

    ReplyDelete
  4. great, i was implemented it, but i've problem. i change class swipeyTabFragment -> extends listfragment. but i implemented loadmore litview in swipey tab, i've got error when i place 'cast' "(LoadMoreListView) getListView())" in onCreateView, how that?

    ReplyDelete
  5. I'm getting an exception when I try to launch Swipey Tabs.

    java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState.

    I downloaded the project directly from the repo.

    ReplyDelete
    Replies
    1. Okay, I just tried it on a Motorola Droid X, and it worked, then tried it the original Samsung GS3 that was getting the error, then it mysteriously started working.

      Thanks very much for this demo!

      Delete