Wednesday, March 13, 2013

Android : Tabs + ViewPager (Swipe-able Tabs, FTW)



To implement a Tabs & ViewPager, using fragments on devices running Android 2.1 or higher, you’ll need to include the Android Compatibility library.  In my example, I’m using Compatibility library v4.

Step-by-step

Define the activity_main layout
Define the PagerAdapter
Define the MainActivity



1)MainActivity.java


package com.jitesh.tabviewpager;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;

import android.support.v4.view.ViewPager;
import android.view.View;
import android.widget.TabHost;
import android.widget.TabHost.TabContentFactory;

/**
 * The <code>TabsViewPagerFragmentActivity</code> class implements the Fragment
 * activity that maintains a TabHost using a ViewPager.
 * 
 * @author jitesh
 */
public class MainActivity extends FragmentActivity implements
TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener {

private TabHost mTabHost;
private ViewPager mViewPager;
private HashMap<String, TabInfo> mapTabInfo = new HashMap<String, MainActivity.TabInfo>();
private PagerAdapter mPagerAdapter;

/**

* @author mwho Maintains extrinsic info of a tab's construct
*/
private class TabInfo {
private String tag;
private Class<?> clss;
private Bundle args;
private Fragment fragment;

TabInfo(String tag, Class<?> clazz, Bundle args) {
this.tag = tag;
this.clss = clazz;
this.args = args;
}

}

/**
* A simple factory that returns dummy views to the Tabhost

* @author mwho
*/
class TabFactory implements TabContentFactory {

private final Context mContext;

/**
* @param context
*/
public TabFactory(Context context) {
mContext = context;
}

/**
* (non-Javadoc)

* @see android.widget.TabHost.TabContentFactory#createTabContent(java.lang.String)
*/
public View createTabContent(String tag) {
View v = new View(mContext);
v.setMinimumWidth(0);
v.setMinimumHeight(0);
return v;
}

}

/**
* (non-Javadoc)

* @see android.support.v4.app.FragmentActivity#onCreate(android.os.Bundle)
*/
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the layout
setContentView(R.layout.activity_main);
// Initialise the TabHost
this.initialiseTabHost(savedInstanceState);
if (savedInstanceState != null) {
mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab")); // set
// the
// tab
// as
// per
// the
// saved
// state
}
// Intialise ViewPager
this.intialiseViewPager();
}

/**
* (non-Javadoc)

* @see android.support.v4.app.FragmentActivity#onSaveInstanceState(android.os.Bundle)
*/
protected void onSaveInstanceState(Bundle outState) {
outState.putString("tab", mTabHost.getCurrentTabTag()); // save the tab
// selected
super.onSaveInstanceState(outState);
}

/**
* Initialise ViewPager
*/
private void intialiseViewPager() {

List<Fragment> fragments = new Vector<Fragment>();
fragments.add(Fragment.instantiate(this, Tab1Fragment.class.getName()));
fragments.add(Fragment.instantiate(this, Tab2Fragment.class.getName()));
fragments.add(Fragment.instantiate(this, Tab3Fragment.class.getName()));
this.mPagerAdapter = new PagerAdapter(
super.getSupportFragmentManager(), fragments);
//
this.mViewPager = (ViewPager) super.findViewById(R.id.viewpager);
this.mViewPager.setAdapter(this.mPagerAdapter);
this.mViewPager.setOnPageChangeListener(this);
}

/**
* Initialise the Tab Host
*/
private void initialiseTabHost(Bundle args) {
mTabHost = (TabHost) findViewById(android.R.id.tabhost);
mTabHost.setup();
TabInfo tabInfo = null;
MainActivity.AddTab(this, this.mTabHost,
this.mTabHost.newTabSpec("Tab1").setIndicator("Tab 1"),
(tabInfo = new TabInfo("Tab1", Tab1Fragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
MainActivity.AddTab(this, this.mTabHost,
this.mTabHost.newTabSpec("Tab2").setIndicator("Tab 2"),
(tabInfo = new TabInfo("Tab2", Tab2Fragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
MainActivity.AddTab(this, this.mTabHost,
this.mTabHost.newTabSpec("Tab3").setIndicator("Tab 3"),
(tabInfo = new TabInfo("Tab3", Tab3Fragment.class, args)));
this.mapTabInfo.put(tabInfo.tag, tabInfo);
// Default to first tab
// this.onTabChanged("Tab1");
//
mTabHost.setOnTabChangedListener(this);
}

/**
* Add Tab content to the Tabhost

* @param activity
* @param tabHost
* @param tabSpec
* @param clss
* @param args
*/
private static void AddTab(MainActivity activity, TabHost tabHost,
TabHost.TabSpec tabSpec, TabInfo tabInfo) {
// Attach a Tab view factory to the spec
tabSpec.setContent(activity.new TabFactory(activity));
tabHost.addTab(tabSpec);
}

/**
* (non-Javadoc)

* @see android.widget.TabHost.OnTabChangeListener#onTabChanged(java.lang.String)
*/
public void onTabChanged(String tag) {
// TabInfo newTab = this.mapTabInfo.get(tag);
int pos = this.mTabHost.getCurrentTab();
this.mViewPager.setCurrentItem(pos);
}

/*
* (non-Javadoc)

* @see
* android.support.v4.view.ViewPager.OnPageChangeListener#onPageScrolled
* (int, float, int)
*/
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// TODO Auto-generated method stub

}

/*
* (non-Javadoc)

* @see
* android.support.v4.view.ViewPager.OnPageChangeListener#onPageSelected
* (int)
*/
@Override
public void onPageSelected(int position) {
// TODO Auto-generated method stub
this.mTabHost.setCurrentTab(position);
}

/*
* (non-Javadoc)

* @see android.support.v4.view.ViewPager.OnPageChangeListener#
* onPageScrollStateChanged(int)
*/
@Override
public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub

}
}


2)PagerAdapter.java

package com.jitesh.tabviewpager;

/**
*
*/

import java.util.List;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

/**
* The <code>PagerAdapter</code> serves the fragments when paging.
* @author jitesh
*/
public class PagerAdapter extends FragmentPagerAdapter {

private List<Fragment> fragments;
/**
* @param fm
* @param fragments
*/
public PagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
/* (non-Javadoc)
* @see android.support.v4.app.FragmentPagerAdapter#getItem(int)
*/
@Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}

/* (non-Javadoc)
* @see android.support.v4.view.PagerAdapter#getCount()
*/
@Override
public int getCount() {
return this.fragments.size();
}
}

3)activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
<TabHost
   android:id="@android:id/tabhost"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
   <LinearLayout
       android:orientation="vertical"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       >
       <TabWidget
           android:id="@android:id/tabs"
           android:orientation="horizontal"
           android:layout_width="fill_parent"
           android:layout_height="wrap_content"
           android:layout_weight="0"
           />

       <FrameLayout
           android:id="@android:id/tabcontent"
           android:layout_width="0dp"
           android:layout_height="0dp"
           android:layout_weight="0"/>

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

4) tab_frag1_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="#FF0000"
  >
</LinearLayout>

5) tab_frag2_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="##bcda"
  >
</LinearLayout>

6) tab_frag3_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="##abcd"
  >
</LinearLayout>

7)Tab1Fragment.java

package com.jitesh.tabviewpager;



import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;



/**
 * @author jitesh
 *
 */
public class Tab1Fragment extends Fragment {
/** (non-Javadoc)
* @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
*/
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist.  The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // won't be displayed.  Note this is not needed -- we could
            // just run the code below, where we would create and return
            // the view hierarchy; it would just never be used.
            return null;
        }
return (LinearLayout)inflater.inflate(R.layout.tab_frag1_layout, container, false);
}
}

8)Tab2Fragment.java

package com.jitesh.tabviewpager;


import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;



/**
 * @author jitesh
 *
 */
public class Tab2Fragment extends Fragment {
/** (non-Javadoc)
* @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
*/
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist.  The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // won't be displayed.  Note this is not needed -- we could
            // just run the code below, where we would create and return
            // the view hierarchy; it would just never be used.
            return null;
        }
return (LinearLayout)inflater.inflate(R.layout.tab_frag2_layout, container, false);
}
}

9)Tab3Fragment.java

package com.jitesh.tabviewpager;


import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;



/**
 * @author jitesh
 *
 */
public class Tab3Fragment extends Fragment {
/** (non-Javadoc)
* @see android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
*/
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (container == null) {
            // We have different layouts, and in one of them this
            // fragment's containing frame doesn't exist.  The fragment
            // may still be created from its saved state, but there is
            // no reason to try to create its view hierarchy because it
            // won't be displayed.  Note this is not needed -- we could
            // just run the code below, where we would create and return
            // the view hierarchy; it would just never be used.
            return null;
        }
return (LinearLayout)inflater.inflate(R.layout.tab_frag3_layout, container, false);
}
}

Download the code from TabViewPager

1 comment:

  1. This comment has been removed by a blog administrator.

    ReplyDelete