Android Adventures - ViewPager
Written by Mike James   
Thursday, 20 November 2014
Article Index
Android Adventures - ViewPager
How FragmentPagerAdapter Works

The ViewPager widget is one of the most used of the advanced UI components. However, the story of how to make use of it is a tricky one. Let's see how simple we can make it. 

Android Adventures - Mastering Fragments & Dialogs

coverfrag

Contents

This book is currently being revised. Chapter 5 and later refer to an earlier version of Android Studio - revisit for updates.

  1. Introducing Fragments
  2. Fragments and Android Studio XML
  3. Static Fragments
  4. Dynamic Fragments (Coming soon)

  5. Fragment And Activity Working Together
  6. Managing Fragments
  7. Custom dialogs using DialogFragment
  8. Dialog Classes In DialogFragment
  9. A NumberPicker DialogFragment Project
  10. ViewPager

If you are interested in creating custom template also see:

Custom Projects In Android Studio

Androidgears

 

One of the widgets that you are going to want to make use of at some time or other is ViewPager. This provides a way to manage multiple pages and lets the user swipe from one page to another. Like ListView it makes use of an adapter to generate its view, but in this case the adapter returns a Fragment which the ViewPager then makes use of to generate a View which it displays.

The fact that we are working with Fragments for pages means that this is a powerful way to work - the Fragment can respond to the user and do things. But it also means that you have to know about Fragments and be completely comfortable with them.

There are a few complicated things that happen in the ViewPager and you can't hope to follow if you are uncertain how Fragments work. If you need to know work about Fragments go to Introducing Fragments and work through this series of articles from that point.

ViewPager - How It Works

The ViewPager class is a layout manager or a container that allows the user to swipe left and right though a set of pages that you supply. The term "pages" suggests something like an web page but this is only a very lose analogy. 

The idea is that ViewPager works with a PageAdapter to supply the Views that represent each page. The basic idea is that ViewPager keeps track of what page should be visible on the screen and then asks the PagerAdapter to get the View hierarchy that needs to be displayed.  For example, the ViewPager might request page 4 and the PagerAdapter generates or otherwise retrieves the View object for the page. 

In practice the low level mechanism of working with a simple PagerAdapter is a bit more tricky than working with a Fragment based PagerAdapter . In this scheme of things each page to be displayed is organised as a Fragment and the View hierarchy that the ViewPager needs is obtained via the Fragment's OnCreateView method. That the page is just what ever the Fragment would display in normal use. 

The idea is that FragmentPagerAdapter either generates or retrieves the Fragment by page number and then internally uses the OnCreateView method to generate the View hierarchy that the ViewPager uses to display the page. 

So for all this to work we need:

  1. An Activity with a ViewPager on display as part of its main UI. 
  2. A set of Fragments to be used as pages
  3. A custom  FragmentPagerAdapter that returns the correct Fragment for each page number.

Let's see how to put this into operation but first a small detail that is essential to allow us to actually use a ViewPage.

 

The Support Library

In most of the other chapters we have made use of native Fragment support. In the case of ViewPager we cannot avoid using the support library because ViewPager isn't natively supported even in the very latest Android, Lollipop.

As the support library doesn't work well with native Fragments we will also have to use the support library's Fragment services. 

To make use of the support library you need to navigate the project structure to Gradle Scripts and open the file build.gradle(app). At the end of the file add a line to the dependencies like:

compile "com.android.support:support-v4:21.0.+"

You can change the 21.0 to what ever version you want to use. The "+" at the end will ensure that you use the most up-to-date sub-version.

The end of the file should read something like:

dependencies {
 compile fileTree(dir: 'libs', include: ['*.jar'])
 compile "com.android.support:support-v4:21.0.+"
}

At this point Android Studio should prompt you to synchronize the project. If it doesn't use the command File Synchronize. 

After this the project is ready for you to use classes that are in the support library and in most cases will automatically add the appropriate import statements for you.

The Simplest Example

There are a few examples of using ViewPager but they all include something extra to show you how amazingly useful ViewPager is. In our first example, the emphasis is on keeping things simple - as simple as possible so that the way that ViewPager works is very obvious.

First we need a new Android Studio project - a blank Activity will do fine. 

The first task is to edit the build.gradle(app) file to include the support library as described in the previous section. Make sure that you have synchronized the project after making the change. 

The Activity

In most examples of ViewPager a layout is prepared with XML to generate the ViewPage. The Android Studio designer doesn't support drag-and-drop editing of the ViewPager widget. You can edit the XML layout directly to insert a ViewPager but you can also generate the ViewPager object in code and add it to the View in the usual way - see, if you are in any doubt about how to work with a View in code, refer back to UI Graphics A Deep Dive.

First we have to clean the generated layout by removing the "Hello World" text and changing the Relative layout to a Vertical LinearLayout - editing the XML file is the quickest way. Also give the LinearLayout an id of container.

The XML you need is:

<LinearLayout xmlns:android=
       "http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools" 
 android:layout_width="match_parent"
 android:layout_height="match_parent"  android:paddingLeft="@dimen/activity_horizontal_margin"
 android:paddingRight="@dimen/activity_horizontal_margin"
 android:paddingTop="@dimen/activity_vertical_margin"
 android:paddingBottom="@dimen/activity_vertical_margin"  tools:context=".MainActivity"
 android:orientation="vertical"
 android:id="@+id/container">
</LinearLayout>

As we need to use the support library we need to change the MainActivity to inherit from FragmentActivity. Edit the class declartion to read:

public class MainActivity extends FragmentActivity {

The code that you need to create a ViewPager and add it to the layout is just:

ViewPager myVP=new ViewPager(this);
myVP.setId(View.generateViewId());
LinearLayout linL =
    (LinearLayout) findViewById(R.id.container);
linL.addView(myVP);

You will be prompted by the Android Studio to let it automatically add the imports needed for ViewPager and LinearLayout. 

The complete onCreate method is: 

protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 ViewPager myVP=new ViewPager(this);
 myVP.setId(View.generateViewId());
 LinearLayout linL =
   (LinearLayout) findViewById(R.id.container);
 linL.addView(myVP);
}

 

You can now run the program but all you will see is a blank ViewPager. 

To see something work we need some Fragment objects to display.

The Fragment

At this point you might be thinking that there is a missing "s" from the title. If we are going to display a number of pages then presumably we need a custom Fragment for each one. Some times we do need multiple custom Fragment classes but the FragmentPagerAdapter works with instances of Fragment classes i.e. Fragment objects. If the pages are roughly the same but with different data then a Fragment class can be reused. 

For simplicity we will only create a single Fragment class that displays its page number. In a more realistic example some of the pages would be generated from different Fragments. 

Right click the project folder and use the New,Fragment,Fragment(Blank) command to add a new Fragment called Page. Unselect Include interface callbacks or remove the code that this option generates. In this case we are not wanting the Fragment to interact with the Activity but it could. 

To customise the Fragment we are going to have to add a TextView to its layout to display the page number. Use the designer to edit the Fragment's layout - fragment_page.xml. You can place any UI widget or component you care to use. This is a completely general UI layout you are creating and you can treat it exactly as you would an layout to be used with an Activity. 

In this case simply place a TextView on the screen.

Next we need to customise the generated code which contains more than we actually need. It also makes use of the native Fragment implementation and we need to change it to make use of the support library. You can skip this step as the native Fragment class will work with the support library ViewPager but using the support Fragment seems to be more stable. 

The simplest way to change to the support library is to delete the existing import 

import android.app.Fragment;

wait a moment for Android Studio to notice and then use Alt-Enter to pick the correct import:

import android.support.v4.app.Fragment;

or you could just type in the new import.

Other changes to the code are about what the Fragment is doing. The Fragment is simply going to display the first parameter supplied via the newInstance method in the TextView that we placed into its layout earlier. Change the onCreateView to read:

public View onCreateView(
         LayoutInflater inflater,
         ViewGroup container,
         Bundle savedInstanceState) {
// Inflate the layout for this fragment
 View v= inflater.inflate(
         R.layout.fragment_page,
         container,
         false);
 ((TextView)v.findViewById(R.id.textView)).
                              setText(mParam1);
 return v;
}

 

This is all we need to do to get a custom Fragment that displays the page number.

Now we need to move on to the custom FragmentPagerAdapter. 



Last Updated ( Saturday, 25 July 2015 )