Horizontal Scrolling Pages of Images in Android

With the Android V4 compatibility library, you can use Fragments even if you are not using Ice Cream Sandwich (API 14+). That opens up some interesting possibilities for your applications, particularly if you want to be more creative in your use of the extra space available on tablets. For this article, I want to focus on another use for fragments:  horizontal scrolling pages.

I started with an article on the Android Developers’ blog: Horizontal View Swiping With View Pager. It is a very useful article that shows you how to get pages of lists scrolling. I wanted to build a demo app of my own that uses pages. Having spent some time reading the new Android Design website, which places heavy emphasis on visual elements, I decided to figure out how to have pages of images that scroll left and right. My inspiration was the section named “Pictures Are Faster Than Words” on the Design Principles page.

My demo app shows pages of images. It has a structure very similar to the Fragments demo that is in the support package. I started with that and replaced the ListView fragments with GridView fragments. Each GridView holds images. Each of the images has a title. When you long-click on an image, you zoom in on the picture, and from there you can click the picture to see the text for the topic. The figures below show what the app looks like.

Pages of topics scroll left and right, or you can jump to the start or the end of the images by touching the “First” and “Last” buttons. To zoom in on the topic of an image, you use a long-click (long press). I did that because the regular touch events are being used so you can scroll pages. A second touch on the enlarged image takes you to the text associated with the image.

In landscape mode, a different arrangement of images exists. On a small device, it shows one row with three images rather than the 2×2 arrangement in portrait mode.

Figure 5 – Layout of images varies in portrait and landscape

Source Code

The source code for this demo application is available here:  download zip from Wglxy.com.  Do a “clean build” in Eclipse if it reports errors immediately after importing the project.

This application has been compiled with API level 10 (2.3.3). It runs on devices and in the emulator from API level 8 to API level 15. It also compiles with 4.03. If you prefer to work at that level, just change the project properties. If you do start your app at the higher level, be sure to do extensive testing at the lower API levels. You want to make sure that you are not using features introduced in API 15 that are not supported in older versions.

How It Works

This demo depends on the ViewPager class in the V4 Compatibility Library. If you download the source code for my demo, you do not have to worry about installation of the support package. It is already in the app libs folder and the project’s build path has already been set correctly. (When you set up your own project, you will want to do those two steps for your project. See the instructions for compatibility library and read Horizontal View Swiping With View Pager. )

The main activity of the demo is the GridViewPager class. It depends on the ViewPager class, which works a lot like ListView and GridView classes. You implement an adapter class that provides the views that it scrolls. The adapter is called by a ViewPager view that you include in the layout for the activity. GridViewPager uses demo_pager.xml for its layout. Inside a FrameLayout and LinearLayout, there is a definition of a ViewPager.


This definition in the layout file indicates where we want the scrolling pages to appear. For this demo, it is right above the definitions for the First and Last buttons.

Let’s examine the GridViewPager class in greater detail. Because it uses fragments, it is a subclass of FragmentActivity, which is one of the classes provided by the compatibility library.
public class GridViewPager extends FragmentActivity 
implements View.OnLongClickListener

In the onCreate method of GridViewPager, an adapter object is created. The adapter there is a bit like an adapter you create when you use ListView and GridView in Android. Rather than providing views that can appear in a list or in a grid, this adapter provides a set of views that can be scrolled left and right as pages. It uses a layout that embeds the ViewPager view from the compatibility class. As shown below, onCreate starts out by defining its content view using the demo_page.xml file. Then there are a few lines to define a collection of images and topics to be used in the demo. Then there is the creation of an adapter object that does the work of creating each individual page. Note the arguments on the constructor. MyAdapter has access to the entire list of topics and the Resources object so it can divide the images up among the pages.

protected void onCreate(Bundle savedInstanceState) {
 // Create a TopicList for this demo. Save it as the shared instance in TopicList
 Resources res = getResources ();
 String sampleText = res.getString (R.string.sample_topic_text);
 TopicList tlist = new TopicList (sampleText);
 TopicList.setInstance (tlist);
 // Create an adapter object that creates the fragments that we need 
 // to display the images and titles of all the topics.
 mAdapter = new MyAdapter (getSupportFragmentManager(), tlist, res);
 mPager = (ViewPager)findViewById(R.id.pager);


Class MyAdapter is defined as a subclass of FragmentStatePagerAdapter, which in turn is a subclass of FragmentPagerAdapter. That class is designed to work with the ViewPager layout class. Its main responsibility is to provide the page views.

public static class MyAdapter extends FragmentStatePagerAdapter
  private TopicList mTopicList;
  private int mNumItems = 0;
  private int mNumFragments = 0;
public MyAdapter (FragmentManager fm, TopicList db, Resources res) {
  setup (db, res);

Note that there are instance variables for the number of images (items) and the number of page fragments. Those are calculated inside the setup method. They are used inside the getCount and getView methods.

 * Get the number of fragments to be displayed in the ViewPager.
@Override public int getCount() {
 return mNumFragments;
 * Return a new GridFragment that is used to display n items at the position given.
 * @param position int - the position of the fragement; 0..numFragments-1
@Override public Fragment getItem(int position) {
 // Create a new Fragment and supply the fragment number, image position, 
 // and image count as arguments.
 Bundle args = new Bundle();
 args.putInt("num", position+1);
 args.putInt("firstImage", position * mNumItems);
 // Most pages hold mNumItems. The last page might not have the full number of items.
 int imageCount = mNumItems;
 if (position == (mNumFragments-1)) {
    int numTopics = mTopicList.getNumTopics ();
    int rem = numTopics % mNumItems;
    if (rem > 0) imageCount = rem;
 args.putInt("imageCount", imageCount);
 args.putSerializable ("topicList", TopicList.getInstance ());
 // Return a new GridFragment object.
 GridFragment f = new GridFragment ();
 return f;

You should be able to see the similarity between this kind of adapter and the ones you use for list views and grid views. For this adapter, getCount returns the number of pages (fragments) rather than the number of items in the list. The getItem method returns a fragment object to be displayed as a page.

Let’s look at GridFragment, which is a subclass of Fragment. It is the object that creates a page of images. Each page uses a GridView object. The number of rows and columns is determined by two integer resource values: grid_num_rows and grid_num_cols. The code section below highlights some of the key parts of GridFragment.

public class GridFragment extends Fragment {
@Override public void onCreate(Bundle savedInstanceState) {
 // Read the arguments and check resource values for number of rows and number of
 // columns so we know how many images to display on this fragment.
 Bundle args = getArguments ();
 mNum = ((args != null) ? args.getInt ("num") : 0);
public void onActivityCreated(Bundle savedInstanceState) {
 // When the activity is created, divide the usable space in the view into columns
 // and put a grid of images in that area.
 Activity a = getActivity ();
 // Connect the gridview with an adapter that fills up the space.
 gridview.setAdapter (new GridImageAdapter (a, mTopicList, 
                                            mFirstImage, mImageCount, 
                                            cellWidth, cellHeight));
public View onCreateView (LayoutInflater inflater, ViewGroup container, 
                          Bundle savedInstanceState) {
 // Build the view that shows the grid.
 View view = inflater.inflate(R.layout.demo_pager_grid, container, false);
 return view;
} // end class GridFragment

There are few things worth noting in the code above:

  • onCreateView is an important method in any Fragment.
    It gives you the opportunity to define the user interface for the fragment. Here, it inflates the layout defined in demo_pager_grid.xml. That’s where the GridView definition is.
  • A GridImageAdapter is a BaseAdpapter subclass that does a bit more work than other adapter classes you might have built.
    It takes a few more arguments in its constructor. The reason I did this is so I could more precisely control  how many images are displayed in the GridView. For a 2×2 grid, for example, I wanted exactly four images to be displayed, and I wanted all of them to be displayed without having to scroll vertically inside the GridView.
  • GridImageAdapter defines a getItem method that creates the views that show up in the GridView.
    Each of the those views is defined by demo_pager_grid_item.xml. It contains a FrameLayout with an ImageView and TextView inside it.
  • onCreateView is an important method in any Fragment.
    It gives you the opportunity to define the user interface for the fragment. Here, it inflates the layout defined in demo_pager_grid.xml. That’s where the GridView definition is.

Grid Layouts

Upon orientation change, the main view of the application switches from a 2×2 grid to a 3×1 grid. That is controlled by having different resource files in the values folders of the application. The number of rows and columns in the grid come from resource values in the dimens.xml file. Check those two files in the values and values-land folders.

Integers in values/dimens.xml:

<integer name="grid_num_rows">2</integer>
<integer name="grid_num_cols">2</integer>

Integers in values-land/dimens.xml

<integer name="grid_num_rows">1</integer>
<integer name="grid_num_cols">3</integer>

Note that there are additional values folders: values-large, values-large-land, values-sw600dp, values-sw600dp-land. Each of those has a dimens.xml file. Those files are used for large screens and tablets. If you follow this approach, you can build an app where the number of images per page is larger for tablets.

I first used this technique when I was adapting my dashboard user interface to tablets.

Rough Spots


I know this demo is bit more complicated than some of the ones I have put together. It has pages of views that are created by an adapter object. Each of the pages has a GridView, and those are also created by an adapter object, but it’s a different kind of adapter object. If you find yourself getting confused by all the different classes, go back to the original example in “Horizontal View Swiping With View Pager“. Be sure you understand paging and fragments well. Then come back to this example.

Managing Bitmaps

A problem I did not address is managing bitmaps. I used relatively small images and not very many of them. I also used the FragmentStatePagerAdapter rather than the other FragmentPagerAdapter. It does something so it holds only the views it needs in memory.

When I get ready to move beyond a demo to a real application, I plan to study “Displaying Bitmaps Efficiently“.

GridView of Images

I wanted to create an app where you could scroll through all the images with horizontal scrolling, rather than the vertical scrolling you can get easily with a GridView. Something that probably needs more work is the way in which I create GridView objects. I came up with a way to use a GridView for each page of images, but I had to go to some extra effort to size the images so there would be no need for vertical scrolling inside the pages.

I am not sure I did that in the easiest manner. I used a DisplayMetrics object and dimension values in dimens.xml.

Activity a = getActivity ();
Resources res = a.getResources ();
DisplayMetrics metrics = new DisplayMetrics();
// From the resource files, determine how many rows 
// and columns are to be displayed.
final int numRows = res.getInteger (R.integer.grid_num_rows);
final int numCols = res.getInteger (R.integer.grid_num_cols);
int availableHeight = metrics.heightPixels - heightUsed; 
int availableWidth = metrics.widthPixels - widthUsed;
int cellWidth = availableWidth / numCols;
int cellHeight = availableHeight / numRows;

By starting with metrics.heightPixels and widthPixels, I had to account for all the different elements that took up vertical and horizontal space.

Since starting this example app, I have found a few examples where people have used TableLayout objects for a collection of images. I intend to take a look at that class and see if that might be a better way to lay out the topic images.

(Update: August 31, 2012. I found a good way to set image sizes for a good fit within a grid while doing another demo app. See my post on Image Squares.)

Converting to Android Ice Cream Sandwich

There is a quick way to change this demo so it works on Ice Cream Sandwich. Follow my guide for getting started with ICS. Change the app so it is being compiled by Android 4.03 (or later). Edit the styles.xml file in the values-v14 in the resource folder. The styles file contains the following:

  <!-- <style name="Theme.Demo" parent="@android:style/Theme.Holo.Light">
  </style> -->
  <dimen name="title_bar_height">36dp</dimen>

Remove the comment markers around the style element. (The comment markers are there so the application builds correctly with Android 2.3.3.)

Basically, for the initial transition to V4, all that you are doing is specifying which of the two Ice Cream Sandwich (ICS) themes you want to use for the title bar. The two choices are Theme.DeviceDefault and Theme.Holo.Light. Running ICS in the emulator, the app looks like this:

Figure 6 – Demo app running on Android ICS


Fragments – detailed information about Fragments and how they fit in with Activity objects.

Horizontal View Swiping With View Pager – a great article that explains how to use Fragments for pages that you can scroll horizontally. This was the starting point for my demo app. I modified the example to have pages of images in grid views.

Compatibility Library– information about the Android support package that allows you to use some V4 (Ice Cream Sandwich) features in Android 2.x applications.

Supporting Tablets and Handsets – provides guidance on supporting both worlds: single and multi-pane applications.

Layout Tricks: Merging Layouts – contains an example of how to stack a TextView on top of an ImageView.

New Tools For Managing Screen Sizes – a blog article that explains how to use the new size qualifiers (e.g. values-sw600dp, layout-sw600dp).

About Bill Lahti

Bill Lahti is an indie game developer. He is currently working on Lifeforms, a two-player game based on Conway’s Game of Life. Other iOS and Android games: Double Star II, Wing Leader, Gomoku League.
This entry was posted in Android and tagged , , , , , . Bookmark the permalink.

16 Responses to Horizontal Scrolling Pages of Images in Android

  1. Pingback: Revue de l’actu Android pro du 20 mai 2012 | Paris Android User Group

  2. hanumantharao says:

    Hi Thanks for your tutorials. Can u please post tutorial on video streaming from network .


    • blahti says:

      Hope the tutorials have helped. I have learned a lot doing them. I don’t have any particular expertise in that area, but it sounds like an interesting topic.

  3. Pingback: My Android Programming Tutorials By Topic « More Is Not Always Better

  4. Cuong says:

    your works are great!
    I am trying to do some software interaction integration on Android and Microsoft surface, and your works help much.

    Thanks for the excelent demos on views and code structures.

  5. shivaprakash says:

    It’s very nice…but I need in horizontal scroll view. Not in grid view

    • blahti says:

      You might want to look at the Horinzontal View Swiping note I reference. It is another example and it has list views scrolling left and right. With this way of doing scrolling, you can choose whatever you want for the fragments that scroll. They do not all have to be the same thing.

  6. kiemduong says:

    Mr blahti,
    How to make a infinite scrolling pages?

    • blahti says:

      This way of doing horizontal scrolling does not have any limit on the number of fragments that you can. Change the adapter to add as many as you want. Practical limits (memory size, for instance) can be addressed to some extent with the second type of adapter. See the Horizontal View Swiping reference

  7. So cool, i’m definitely going to use it…

  8. venu says:

    Thanks for the post…..I am looking for application same as Dolphin browser which allows to scroll the pages horizontally and can show partial left page and partial rightpage and It allows to do actions on visibility part of those partial pages.

    Plz help me

  9. Manuel Rojas says:

    Hi. Thanks a lot for the post. I have a problem and wanted to see if anyone could help me with it. I have an horizontal pagination pretty much like the one in this tutorial. But I’m trying to insert a edittextbox inside of every item in the gridview. The problem is that it works fine for all of the items in the gridview but for the first one. The first item (first colum, first row) when I click on the edittextbox to add some text, it doesn’t take the focus. But it’s even weirder because I yet try to write something in this first edittextbox and when I clicked outside like setting focus out, it’s right in that moment when it comes over to show the written text.

    Does anybody have an idea about this issue?

    Thanks a lot in advance.

    • blahti says:

      One thing to check is where you are recycling views in your adapter. Whenever I have seen odd behavior in my apps like this, it has turned out to be something that I did not do to clear out a view properly to it could be used again.

  10. I cant download! Please review the link!

    • Bill Lahti says:

      Sorry,something has changed with the Google doc viewer. I think this affects Chrome browser users. Use the download icon on the wglxy.com page for the demo app. The download icon is to the right of the date and the version number. That one works fine.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.