Android – Using the ViewPager
by Riley MacDonald, January 16, 2015

The Android ViewPager is a view which allows users to swipe left and right through pages of data. It uses an instance of PagerAdapter to generate pages which the ViewPager displays. Several tutorials demonstrate using the ViewPager in conjunction with a Fragment, however if you are not working directly with an Activity this can be difficult. My experience implementing a ViewPager using Android’s documentation and search results was mildly frustrating.

The following is a demonstration of how to implement Android’s ViewPager using the PagerAdapter:

Include a ViewPager in your desired layout:

<android.support.v4.view.ViewPager
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/my_view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</android.support.v4.view.ViewPager>

Failing to use the support ViewPager can cause your application to have a RuntimeException and crash:

java.lang.RuntimeException: Unable to start activity android.view.InflateException: Binary XML file line #28: Error inflating class ViewPager
Caused by: java.lang.ClassNotFoundException: Didn't find class "android.view.ViewPager" on path: DexPathList

Implementing the ViewPager:
For this demonstration I’m using a custom view to hold the ViewPager. This custom view includes an inner subclass of PagerAdapter which will manage the ViewPager views. The class is described in the code / comments below. The comments describe the purpose / usage of the required override methods of PagerAdapter instantiateItem(), getCount(), isViewFromObject() and destroyItem(). Also included is getItemPosition() which is helpful when modifying, adding and deleting items from the dataset / ViewPager.

import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
 
// For this demonstration I'm using using a custom frame layout to hold the view pager.
public class MyFrameLayout extends FrameLayout {
    // Views
    private MyViewPagerAdapter myViewPagerAdapter; // View Pager Adapter
    private ViewPager myViewPager; // View Pager
 
    // Layout inflater for creating views
    private LayoutInflater inflater;
 
    // FrameLayout Constructors
    public MyFrameLayout(Context context) { super(context); }
    public MyFrameLayout(Context context, AttributeSet attrs) { super(context, attrs); }
    public MyFrameLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
 
    // Sample initializtion method to setup the views when ready
    public void initialize() {
    	// Grab a reference to the ViewPager
    	myViewPager = (ViewPager) findViewById(R.id.my_view_pager);
 
    	// Construct a new PagerAdapter to manage the pages of the ViewPager
    	myViewPagerAdapter = new MyViewPagerAdapter(); // Inner class - see below
 
    	// Set the ViewPagers adapter
    	myViewPager.setAdapter(myViewPagerAdapter);
 
    	// Construct the layout inflater
    	this.inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }
 
    // Inner subclass of PagerAdapter to manage the ViewPager views
    class MyViewPagerAdapter extends PagerAdapter {
    	// Constructor
        public MyViewPagerAdapter() {}
 
        // Required Override for the ViewPager to function properly.
        // The value returned here is used referenced by the ViewPager. If getCount() returns 0, no views will be created.
        // This is best used with a data set. Set this to return the size of your data set.
        // Using a default value of 5 to display 5 pages for this demonstration.
        @Override public int getCount() { return 5; }
 
        // Required Override for the ViewPager to function properly.
        // Determines whether a page View is associated with a specific key object as returned by instantiateItem(ViewGroup, int). 
        @Override public boolean isViewFromObject(View view, Object o) { return view == o; }
 
        // Required Override for the ViewPager to function properly.
        // Removes a page for the given position. Called automatically by ViewPager as needed.
        @Override
        public void destroyItem(ViewGroup container, int position, Object object) { container.removeView((View) object); }
 
        // Required Override for the ViewPager to function properly.
        // Creates pages for the given position automatically.
        // This function will fire automatically as required. On instantiation this will fire twice, once for
        // page one, once for page two. As users scroll it will fire to ensure views exist ahead and behind the active
        // item. This function was confusing to me initially.
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            // Inflate (and modify) the desired layout to add to the ViewPager.
            FrameLayout item = (FrameLayout) inflater.inflate(R.layout.view_to_add_to, container, false);
 
            // Add the inflated item to the ViewPager
            container.addView(item);
 
            // Ensure the item created and added to the container is returned
            return item;
        }
 
        // Used internally by the adapter when calling notifyDataSetChanged(). This method is referenced during this
        // call. Returning POSITION_NONE cases the previously created views to be destroyed and new ones created.
        // This was a big gotcha for me when modifying the data set to remove or add views from the ViewPager.
        @Override
        public int getItemPosition(Object object) { return POSITION_NONE; }
    }
}

Using Datasets / Modifying, adding and removing pages / views from the ViewPager:
Once you have an instance of PagerAdapter hooked to your ViewPager there is no need to call the remove() or add() methods of the view pager, the PagerAdapter handles it all. Keep the following in mind when using a dataset (whichever works best for you) with the PagerAdapter:
getCount() should return the size of your dataset.
instantiateItem() provides a position argument which can be used to get data from your dataset.
notifyDataSetChanged() Call this after changing the associated dataset. This is the only call required to update the ViewPager pages / views, it will use the PagerAdapter instantiateItem() and destroyItem() calls automagically.
getItemPosition() A bit of a trick when modifying the dataset / views in the ViewPager. Returning POSITION_NONE will remove all views from the ViewPager when a dataset change is made (and notifyDataSetChanged() is called). Since I did not use setOffscreenPageLimit() the ViewPager should only be dealing with a maximum of 3 views so I consider this OK.

I hope this helps other potentially confused developers when implementing this view!

Open the comment form

Leave a comment:

Comments will be reviewed before they are posted.

User Comments:

Android – Using the ViewPager | Riley MacDonald - Jacob is studying on web programming on 2017-05-12 06:04:59 said:
[…] Android – Using the ViewPager | Riley MacDonald […]