Saturday 15 February 2014

Using ViewPager to swipe between Fragments in an ActionBar

In this tutorial I'll  briefly explain how to use the ViewPager widget to swipe between different Fragments in an ActionBar.
In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment, and be able to swipe between them with a smooth animated transition.

In the following example the ViewPager manages the loading of the Fragments, but the widget has to be synchronized with the ActionBar, in other words:

  1. when you swipe to a different Fragment, the ActionBar must select the correct Tab;
  2. when you select a Tab in the ActionBar the ViewPager must select the correct Fragment.


1) XML FILE OF THE MAIN ACTIVITY


<?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:orientation="vertical" >
    
    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


</LinearLayout>

As you can see you have to place the ViewPager widget (here named "pager"), which is provided by the android.support.v4 library, in your layout. We set layout_width and layout_height attributes both to "match_parent" in order to make sure that the ViewPager covers the entire display.

2) MAIN ACTIVITY AND FRAGMENTS: IMPORTS

To be able to use the ViewPager widget you have to use the classes provided by the support library, not the standard library:

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

import android.support.v4.view.ViewPager;

In addition to that your main Activity must extend FragmentActivity, not the standard Activity class:

public class MainActivity extends FragmentActivity {
...
}

Make sure to import the Fragment class provided by the support library also in the classes of each Fragment displayed by the ActionBar through our ViewPager:

import android.support.v4.app.Fragment;

...

public class FragmentOne extends Fragment {
...
//the code of the Fragments is omitted for brevity
...
}


3) ONCREATE METHOD OF THE MAIN ACTIVITY

In the onCreate method of the main Activity we have to create the Fragments used to display our data, the ActionBar and setup the ViewPager widget to be able to swipe between different Fragments.
Here is the code:

@Override
protected void onCreate(Bundle savedInstanceState){
   super.onCreate(savedInstanceState);

setContentView(R.layout.main_activity);

    //first we create the Fragments
    firstFragment = new FirstFragment();
secondFragment = new SecondoFragment();
thirdFragment = new ThirdFragment();
fourthFragment = new FourthFragment();

//now we put the Fragments in an array to use them with the ViewPager
arrFragment = new Fragment[4];
arrFragment[0] = firstFragment;
arrFragment[1] = secondFragment;
arrFragment[2] = thirdFragment;
arrFragment[3] = fourthFragment;

    //now we create an adapter between our Fragments and the ViewPager
    //for this purpose we use and instance of our class MyAdapter, which is 
    //explained later
myFragmentPagerAdapter = new MyAdapter(getSupportFragmentManager());
myViewPager = (ViewPager) findViewById(R.id.pager);
    //we load 3 pages in memory on both sides of the current page
    //pages beyond this limit are recreated from the adapter when needed
myViewPager.setOffscreenPageLimit(3); 

myViewPager.setAdapter(myFragmentPagerAdapter);

//here we set up our ActionBar
setupTabs();

myViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
      @Override
public void onPageSelected(int position) {
getActionBar().setSelectedNavigationItem(position);
}
});
}

With the method setOnPageChangeListener we set a listener that will be invoked whenever the page changes or is incrementally scrolled. 
In this case we retrieve a reference of our ActionBar and select the Tab at the position specified by the ViewPager. In this example we have 4 tabs (see next paragraph), so let's select the Tab at the specified position.


4) SETTING UP THE ACTION BAR.

In our example we not only want to swipe between Fragments using a ViewPager widget: we also need to set up an ActionBar, where each Tab contains a different Fragment.
The method setupTabs(), called from onCreate, creates the ActionBar, the 4 Tabs and sets up a connection between the ActionBar and the ViewPager widget.
Basically we register a listener, called every time a Tab is selected (pressed), which forces the ViewPager to change page (load a different Fragment) with a smooth transition:

private void setupTabs() {
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
ActionBar.TabListener tabListener = new ActionBar.TabListener() {

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
myViewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub

}
  };

     actionBar.addTab(actionBar.newTab().setText(R.string.tab_one).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_two).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_three).setTabListener(tabListener));
actionBar.addTab(actionBar.newTab().setText(R.string.tab_four).setTabListener(tabListener));

}

5) ADAPTER

To make all things work we need an Adapter class (inner class of the main Activity class) to link our Fragments with the ViewPager widget:

public class MyAdapter extends FragmentPagerAdapter {
private final int PAGE_COUNT = 4;

public MyAdapter(FragmentManager fm) {
super(fm);
}

@Override
public Fragment getItem(int i) {
return arrFragment[i];
}

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

@Override
public CharSequence getPageTitle(int position) {
switch(position) {
case TAB_ONE:
return getResources().getString(R.string.tab_one);
case TAB_TWO:
return getResources().getString(R.string.tab_two);
case TAB_THREE:
return getResources().getString(R.string.tab_three);
case TAB_FOUR:
return getResources().getString(R.string.tab_four);
 
   default:
return null;
}
}
}

where of course:

//constants
private static final int TAB_ONE = 0;
private static final int TAB_TWO = 1;
private static final int TAB_THREE = 2;
private static final int TAB_FOUR = 3;


As you can see from the previous example we have:

  1. a ViewPager widget which loads our Fragments through the class MyAdapter defined above;
  2. an ActionBar which forces the ViewPager to load the correct Fragment each time a Tab is selected (pressed);
  3. a listener linked to our ViewPager which selects the correct Tab whenever the user swipes to a different Fragment.

No comments:

Post a Comment