ViewPager / ViewPagerIndicator

ViewPager – Part 2

Important note: There is a more recent article which covers a newer version of ViewPagerIndicator. Please refer to this in conjunction with this article

In the part 1 we got a simple ViewPager working with a TitlePageIndictor. This gave us some pretty impressive results for a relatively small amount of effort. But, given that this blog is focussed on making things look good, what about if you want to change things?

Firstly, let’s change the blue line and arrow on the TitlePageIndicator to be green. First let’s create a style file in res/values/styles.xml:

[xml]


[/xml]

Now let’s modify the layout in res/layout/main.xml to add the style to the TitlePageIndicator:

[xml]




[/xml]

Regular readers of this blog should be pretty familiar with what’s going on here, so I won’t go in to unnecessary detail. The key thing is that Jake has exposed some attributes which allow us to style the control. You can view the available attributes in his attrs.xml. I won’t bother to detail all of the styleable attributes of Jake’s control as I think that the annotations in attrs.xml are fairly self-explanatory. For further details of how styleable attributes work, please refer to the articles on Custom Controls.

If we run this:

A styled TitlePageIndicator
A styled TitlePageIndicator

The next thing that we’ll look at is how well multi-directional scrolling works. Getting a vertically scrolling widget working inside a horizontally scrolling parent layout has caused many an Android programmer problems. How does ViewPager cope? Extremely well! Let’s modify our ViewPagerAdapter to include a ListView rather than a simple TextView. We’ll change the instantiateItem() and destroyItem() methods:

[java] @Override
public Object instantiateItem( View pager, int position )
{
ListView v = new ListView( context );
String[] from = new String[] { “str” };
int[] to = new int[] { android.R.id.text1 };
List> items =
new ArrayList>();
for ( int i = 0; i < 20; i++ ) { Map map =
new HashMap();
map.put( “str”, String.format( “Item %d”, i + 1 ) );
items.add( map );
}
SimpleAdapter adapter = new SimpleAdapter( context, items,
android.R.layout.simple_list_item_1, from, to );
v.setAdapter( adapter );
( (ViewPager) pager ).addView( v, 0 );
return v;
}

@Override
public void destroyItem( View pager, int position, Object view )
{
( (ViewPager) pager ).removeView( (ListView) view );
}
[/java]

Once again, this should be fairly self-explanatory to regular readers of this blog. If we run this:

ViewPager containing ListViews
ViewPager containing ListViews

Again, a screen shot really does not do this justice. I would suggest running this up on a device and you’ll see that horizontal gestures control the ViewPager and vertical ones control the ListView. It is smooth and responsive, yet we have had to do nothing special as far as focus handling is concerned – that is done for us by the ViewPager.

There is one thing that is worth pointing out: If you go to page 1, scroll to the bottom of the ListView, then page across to page 3, and then page back to page 1, the position of the ListView has reset to position 1. The reason for this is that ViewPager will destroy the ListView and re-create it. In the next part of this series we’ll look at how we can overcome this issue.

The source for this article can be found here. Once you checkout the code, you’ll need to manually add the compatibility library, and add ViewPagerIndicator as an Android library as we did in part 1 of this article.

© 2011 – 2012, Mark Allison. All rights reserved.

Copyright © 2011 Styling Android. All Rights Reserved.
Information about how to reuse or republish this work may be available at http://blog.stylingandroid.com/license-information.

20 Comments

    1. Think of the ViewPagerAdapter as being the same as a ListAdapter. You create the item views in exactly the same way.

    2. Accroding to the considerations, I am also trying to insert the Layout such lke LinearLayout into the viewpager. Actually I tried to get LinearLayout using inflater and I finally see the Activity in the viewpager. But If I swife few times, it shows Fatal Error:main. Maybe you can also try to use inflater to implement it.

      1. I really don’t have the time to provide developer support on this site. If you have a specific problem I would suggest StackOverflow.com.

  1. Thanks!

    Do you know if it would be terribly difficult to use images above the Page 1, Page 2 text views in the ViewPager?

    1. Hi Andrew,

      If you want to use images in the ViewPagerIndicator, you’ll need to adapt Jake Wharton’s code.

      Cheers,

      Mark

  2. Mark,

    Thanks for pointing out that you are did ListViews in part 2. I can’t believe I missed that.

    Anyway, I’m still struggling with how to use different lists in the adapter. And how to generate those lists from arrays in strings.xml. 🙂

  3. Wonderful series of posts on the ViewPager. We are having a problem with synchronized scrolling – horizontal and vertical – of content within a ViewPager and also being able to swipe/touch the ViewPager indicator bar to switch between pages.

    For example, in the listview scenario in your post, what if the listview could also be scrolled horizontally. This then requires changing ViewPager views by swiping/touching the ViewPager indicators.

    Is this possible?

    1. The problem is that if you have a horizontally scrolling control within the ViewPager, then both your control and the ViewPager want to handle horizontal scrolling. You could look at handling gestures such as swipes in the ViewPager and scrolling in your control, but that can get quite complex, and is beyond the scope of what I’m currently looking to cover on this blog. Also, spare a thought for your user: having a horizontal swipe do one thing and a horizontal drag doing something else could be unintuitive, and / or downright confusing.

      Without an understanding of precisely what behaviour you are trying to achieve it is almost impossible for me to advise you further. Also, I simply do not have the time to provide technical support on this blog.

  4. Thank you for useful articles about ViewPager. One little question – why (although pager is from ViewGroup) it is not possible to click “through” it while it is possible in Frame or RelativeLayout? Because of touch-scroll-swipe functionality?

    1. The Android standard is for three years visible items (see the latest Market app) and Jake has implemented this. I would strongly recommend that you stick to the standard model as it will be what your users will be familiar with from other apps and Android itself. If you have a very compelling reason to deviate from the standard, then you’ll need to fork Jake’s repo and modify it to offer the behaviour that you require.

  5. When inflating different layout inside i am getting java.lang.classcastexception: android.widget.linearlayout…. when using more than two layout and while swiping to 3rd layout…. i am unable to find the error. there is no problem in layout definations. I am creating layout using Relative layout inside a linerlayout

  6. First of all,nice tutorial cuz if shows using ViewPager Indicator through activity and for me making transition from activity to fragment,it was a great article. Thanks for it.
    Further, as you all have read the TitlePageIndicator package has been changed,so update accordingly.
    Why I am writing this is that there was always a error telling that “couldn’t load class com.viewpagerindicator.TitlePageIndicator”
    If you all are using adt 17> ,then this case may come.So for that keep following things in mind
    1: If you have to add jar android-support-v4.jar ,put it on libs folder instead of lib folder
    2: If you are using a new version of android-support-v4.jar,then add the same jar on viewpager_indicator core /source files

    This solution has worked for me and hope this helps any troubled developer facing problem like me.

Leave a Reply

Your email address will not be published. Required fields are marked *

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