Skip to content


Quick guide to enabling Tab + Swipe using Fragments and Android Support library

Before you start, if you want a systematic view (abeit a long one) to creating lateral navigation, refer to the Android Developer patterns:

I will go through a step-by-step (condensed version of the various google dev docs pages) on how to implement 3 tabs + swipe using 3 fragments. 2 fragments have xml layout files, and one fragment is a Google MapFragment.


*Important* – All the packages that you will see below such as ViewPager, FragmentActivity etc are available natively to Android 3.0+ APIs, however Android has provided a support library that allow the creation of everything described here all the way down to Android 2.2. This is important, because if you are developing on a high API level you will see that many classes can be important from either native API, or from android.support.*. You will have to stick with one of them as they are not interchangeable.

Example below will be using android support, as this provide greater backward compatibility.


Step 1 – Set up the tabs on the main activity
In Android 3.0+, tabs can be built into the ActionBar on any application. The code below is all that is required:

private void setupABar() {
		// obtain the action bar
		final ActionBar aBar = getActionBar();
                // set it to tab mode
		aBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
		// add a tab listeners to handle changing the current fragment
		ActionBar.TabListener tabListener = new ActionBar.TabListener() {
			@Override
			public void onTabUnselected(Tab tab, FragmentTransaction ft) {

			}

			@Override
			public void onTabSelected(Tab tab, FragmentTransaction ft) {
				mViewPager.setCurrentItem(tab.getPosition());
			}

			@Override
			public void onTabReselected(Tab tab, FragmentTransaction ft) {

			}
		};
		// add the tabs, register the event handler for the tabs
		aBar.addTab(aBar.newTab().setText("Controls").setTabListener(tabListener));
		aBar.addTab(aBar.newTab().setText("Map").setTabListener(tabListener));
		aBar.addTab(aBar.newTab().setText("Stats").setTabListener(tabListener));
	}

and in onCreate, call:

setupABar();

Most of the code here is self-explanatory, except for the mViewPager variable. This will become clear in the next section, just remember that the code above just sets up the tabs and registers a handler. It is rather detached from the whole fragment and swipe process.


Step 2 – Fragments
We now want to build 2 fragments (the 3rd Google Map fragment will be constructed in code at runtime). Here we will show the creation of only 1 fragment called ControlFragment (for the control panel of the app I was building):

ControlFragment.java:

public class ControlFragment extends Fragment {
	
	@Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
		// inflat and return the layout
		return inflater.inflate(R.layout.controls_fragment, container, false);
	}
	
}

and the layout:

controls_fragment.xml (simplified):

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_vertical|center_horizontal"
    android:orientation="vertical" >

    <Button
        android:id="@+id/btn_turnon"
        android:layout_width="146dp"
        android:layout_height="wrap_content"
        android:text="@string/controls_btn_turnon" />
     
    <Button
        android:id="@+id/btn_turnoff"
        android:layout_width="146dp"
        android:layout_height="wrap_content"
        android:text="@string/controls_btn_turnoff" />

</LinearLayout>

Step 3 – ViewPager on the MainActivity and swipe
To support multiple views (called fragments), you generally:

  • Add a ViewPager to the layout (through either the XML or by code), it is responsible for displaying different fragments
  • If you need to control how the ViewPager functions such as disabling swiping on certain fragments, then you need to inherit the default ViewPager
  • Register a bunch of fragments to the ViewPager

Step 2 shows the construction of list items 1 and 2. We are building a custom ViewPager as we want to disable scrolling later on a Google MapFragment (so that when you swipe on the map it doesnt jump to the next tab).

MainActivity.xml (Layout XML):

<com.jamesyxu.jwifivisualizer.ViewPagerMapNoScroll
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

MainActivity.java:

        vertCollectionPagerAdapter mVCollectionPageAdapter;
	ViewPagerMapNoScroll mViewPager;
	
	private void setupPager() {
                // the page adapter contains all the fragment registrations
		mVCollectionPageAdapter = new vertCollectionPagerAdapter(getSupportFragmentManager());
		mViewPager = (ViewPagerMapNoScroll) findViewById(R.id.pager);
                // set the contents of the ViewPager
		mViewPager.setAdapter(mVCollectionPageAdapter);
		// add a on page change listener to change the actionBar's selected tab # (fragment will then be changed by actionBar's code)
                // the change listener is called on swiping
		mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
				@Override
				public void onPageSelected(int pos) {
					getActionBar().setSelectedNavigationItem(pos);
				}
			}
		);
	}

and in onCreate of MainActivity:

setupPager();

*Swiping* – We see that we can enable swiping very easily by implementing a ViewPager’s setOnPageChangeListener, this is triggered whenever a ViewPager detects enough side scrolling, and also has determined that the current fragment can be scrolled (see ViewPagerMapNoScroll.java:canScroll() below).

vertCollectionpagerAdapter.java:

public class vertCollectionPagerAdapter extends FragmentPagerAdapter {
	
	private static final int FRAGMENT_COUNT = 3;
	private List<Fragment> mFragments = new ArrayList<Fragment>();
        // Google's Android MAP API 2 has MapFragment and the Android Support library's equivalent, SupportMapFragment
	private SupportMapFragment mMapFragment;
	private FragmentManager mFM;
	
	public boolean disableSwipe = false; 
	
	public vertCollectionPagerAdapter(FragmentManager fm) {
		super(fm);
		
		mFM = fm;
		
		// add fragments
		mMapFragment = SupportMapFragment.newInstance();
		mFragments.add(new ControlFragment());
		mFragments.add(mMapFragment);
		mFragments.add(new StatsFragment());
	}

	@Override
	public int getCount() {
		return FRAGMENT_COUNT;
	}
	
        // This is called by the ViewPager to get the fragment at tab position pos
        // ViewPager calls this when the Tab handler handles a tab change
	@Override
	public Fragment getItem(int pos) {
		Fragment f = mFragments.get(pos);
                // we want to disable swiping on the map fragment
		if (f instanceof SupportMapFragment)
			disableSwipe = true;
		else
			disableSwipe = false;
		
		return f;
	}
	
	public Fragment getActiveFragment(ViewPager container, int pos) {
		String name = "android:switcher:" + container.getId() + ":" + pos;
		
		return  mFM.findFragmentByTag(name);
	}
	
}

and ViewPagerMapNoScroll.java:

public class ViewPagerMapNoScroll extends ViewPager {
	
	public ViewPagerMapNoScroll(Context context) {
		super(context);
	}
	
	public ViewPagerMapNoScroll(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
	
	@Override
	protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
		if (v instanceof ViewPagerMapNoScroll) {
                        // the vertCollectionPagerAdapter has logic on getItem that determines if the next fragment should have swipe disabled
			vertCollectionPagerAdapter a = (vertCollectionPagerAdapter) ((ViewPagerMapNoScroll)v).getAdapter();
			if (a.disableSwipe)
				return false;
			else
				return true;
		}
		
		return super.canScroll(v, checkV, dx, x, y);
	}
	
}

This completes a really fast, code-centric tutorial on how to build Tab + Swipe using fragments and Android Support library.

As of now, the MapFragment would not work because that require additional setup, see the next blog post on that

Posted in Android, Java. Tagged with , , , , , , , .