Important note: There is a more recent article which covers a newer version of ViewPagerIndicator. Please refer to this in conjunction with this article
At the end of part 2 of this series, we had added ListView controls to each of our ViewPager views, but we lost the scroll position when we moved away from the view. Let’s look at how we can implement the scroll state persistence.
We need to store the scroll position for each of our views within the ViewPager, and we’ll create a simple integer array to hold these values, which we initialise in our constructor:
[java]
public class ViewPagerAdapter extends PagerAdapter implements TitleProvider
{
.
.
.
private int[] scrollPosition = new int[titles.length];
public ViewPagerAdapter( Context context )
{
this.context = context;
for ( int i = 0; i < titles.length; i++ )
{
scrollPosition[i] = 0;
}
}
.
.
.
}
[/java]
Next we need to add an OnScrollListener to each ListView which will detect scroll events, and save the first visible item when the scroll changes (lines 21-37). Also we need to set the scroll position using setSelection() on the ListView when we instantiate a new one (line 20). This is all done in the instantiateItem() method of ViewPagerAdapter:
[java]
@Override
public Object instantiateItem( View pager, final int position )
{
ListView v = new ListView( context );
String[] from = new String[] { “str” };
int[] to = new int[] { android.R.id.text1 };
List
You can only have one Activity at any given time, and that is the container of your ViewPager & ViewPagerIndicator. Maybe you misunderstand what an Activity is if you want to host them inside the ViewPager.
As I said before, you can only have one Activity at any one time. This must wrap the ViewPager & ViewPagerIndicator. So, no, you can’t have a separate Activity for each page. Maybe you should consider using Fragments instead.
Thanks for the guides! Really helped me a lot in doing the swipey. But one question… Is it possible to have both textview and list view in the Viewpager and the text in the textview changes when it’s swipe to the other titles?..
Try implementing an OnPageChangeListener and set this to your ViewPager.setOnPageChangeListener(). In the onPageSelected() method you can do something to trigger the required update to your TextView. I’ve not tried this, so it’ll probably require a bit of trial and error on your part to get it working.
Two things i’d really like to see is maybe a part 4 where you could show how you would show your list view in one page and then a text view in the other and then how to add your own items to the list view
I’m currently writing a series of articles specifically covering ListView. They will be published in the coming weeks. Hopefully they will answer the questions that you have.
Hey Mark, love the blog. I’m having trouble getting the PagerAdapter to refresh the pages. The limited docs say that it has a method notifyDataSetChanged() just like how BaseAdapter (for listviews, gridviews, etc) has one. But calling the method does not cause the current page (and possibly the surrounding 2 pages) to be recreated.
My pages are populated with images loaded from the internet. And sometimes I need to replace the pages with a new set of images. I can’t figure out how to get around this other than to remove and recreate a new ViewPager along with a PagerAdapter.
On a side note, I agree with George in that it would be nice to see how to populate a ViewPager with heterogeneous content similar to how the new Market app has it.
Some explanation of the other inherited methods would also be enlightening.
Thanks for this guide.
I don’t know if it’s a device-specific problem, but I have had the problem that the position was sometimes reset to 0 when switching pages. So I started playing around and found out that it seems to be cured when using the onScrollStateChanged method for saving the position, such as follows:
@Override
public void onScrollStateChanged( AbsListView view, int scrollState ) {
switch(scrollState) {
case SCROLL_STATE_IDLE:
scrollPosition[position] = view.getFirstVisiblePosition();
break;
}
}
Might also be slightly more performant as the value will be saved only once per fling. Although I am unsure about trackballs as the docs indicate that trackball navigation takes completely place in the idle state.
Nice series of posts…Hats off for all the hard work going into integrating the stuff from Jake Wharton,Richard Hyndman and Kirill Grouchnikov (thanks to them as well)…Second the opinions by George and Tony…Looking forward to the next series…
I have been able to work with the tutorial to render a custom listview in the pageadapter. I have five pages and all pages are properly displayed. The list supports clicking of items, its a news feed to enable users view the news body. I realise that while on page two, if i click a news item in page 3 its the news content displayed will be that of the adjacent news item i.e page 2 or 3.
I noticed that the reason for this is because the instantiate item method creates adjacent pages when the user changes views so as to aid fast loading. I handled my click events inside the instantiate item method so what is happening is that when the adjacent view is instantiated and the user clicks one of the list items in the current view, the adjacent view content is what is displayed. I thought to ask the appropriate way to handle events for multiple listviews in the viewpager.
I would like to add ListView on 1st Tab, Google Map on 2nd tab and so on. Different controls on different tabs. I modified your instantiateItem() to display ListView only on 1st tab. Trying to add Google map on 2nd tab. How to attach MapActivity to this 2nd Tab/pager? Pager doesn’t allow starting intent to MapView class. Any hints?
Thanks for your guides. They helped me a lot.
But I have a question… Is there any way to set active ViewPager page? I’ve asked it in SO, but, unfortunately, there is still no answer.
http://stackoverflow.com/questions/7424562/how-to-change-active-viewpager-page
I’ve answered on stackoverflow as others are more likely to see the answer there than in the comments of my blog.
Here’s an implementation of the market’s swipey tabs:
https://github.com/astuetz/android-viewpagertabs
Good day
I am waiting on fire for an example with activities. I am taking out that it is some how difficult to be achieved. Thanks
You can only have one Activity at any given time, and that is the container of your ViewPager & ViewPagerIndicator. Maybe you misunderstand what an Activity is if you want to host them inside the ViewPager.
Good day Mark
Thanks for the answer at first. What i meant is that we can have an activity at every page or have got it wrong? Thanks
Hi Christopher,
As I said before, you can only have one Activity at any one time. This must wrap the ViewPager & ViewPagerIndicator. So, no, you can’t have a separate Activity for each page. Maybe you should consider using Fragments instead.
Thanks Mark
got it.
Thanks for the guides! Really helped me a lot in doing the swipey. But one question… Is it possible to have both textview and list view in the Viewpager and the text in the textview changes when it’s swipe to the other titles?..
Hi Alvin,
Try implementing an OnPageChangeListener and set this to your ViewPager.setOnPageChangeListener(). In the onPageSelected() method you can do something to trigger the required update to your TextView. I’ve not tried this, so it’ll probably require a bit of trial and error on your part to get it working.
I hope this helps.
Regards,
Mark
Two things i’d really like to see is maybe a part 4 where you could show how you would show your list view in one page and then a text view in the other and then how to add your own items to the list view
Nonetheless great write up should be helpful
o and an onclick would be a nice addition to the list view you made
I’m currently writing a series of articles specifically covering ListView. They will be published in the coming weeks. Hopefully they will answer the questions that you have.
okay looking forward to it thanks a ton for the guide!
Hey Mark, love the blog. I’m having trouble getting the PagerAdapter to refresh the pages. The limited docs say that it has a method notifyDataSetChanged() just like how BaseAdapter (for listviews, gridviews, etc) has one. But calling the method does not cause the current page (and possibly the surrounding 2 pages) to be recreated.
My pages are populated with images loaded from the internet. And sometimes I need to replace the pages with a new set of images. I can’t figure out how to get around this other than to remove and recreate a new ViewPager along with a PagerAdapter.
On a side note, I agree with George in that it would be nice to see how to populate a ViewPager with heterogeneous content similar to how the new Market app has it.
Some explanation of the other inherited methods would also be enlightening.
Did you solve this issue?
am i wrong somewhere? cos after press back button for quit app, then open again it still restart at item 1
Thanks for this guide.
I don’t know if it’s a device-specific problem, but I have had the problem that the position was sometimes reset to 0 when switching pages. So I started playing around and found out that it seems to be cured when using the onScrollStateChanged method for saving the position, such as follows:
@Override
public void onScrollStateChanged( AbsListView view, int scrollState ) {
switch(scrollState) {
case SCROLL_STATE_IDLE:
scrollPosition[position] = view.getFirstVisiblePosition();
break;
}
}
Might also be slightly more performant as the value will be saved only once per fling. Although I am unsure about trackballs as the docs indicate that trackball navigation takes completely place in the idle state.
i didnt find style
#14A804
underline
3dp
1.5dp
6dp
#14A804
to make it runnable 🙁 can u plz help me?
It’s in res/values/styles.xml
Great tutorial!!!!
Nice series of posts…Hats off for all the hard work going into integrating the stuff from Jake Wharton,Richard Hyndman and Kirill Grouchnikov (thanks to them as well)…Second the opinions by George and Tony…Looking forward to the next series…
Hi, great post, its been very helpful o me.
I have been able to work with the tutorial to render a custom listview in the pageadapter. I have five pages and all pages are properly displayed. The list supports clicking of items, its a news feed to enable users view the news body. I realise that while on page two, if i click a news item in page 3 its the news content displayed will be that of the adjacent news item i.e page 2 or 3.
I noticed that the reason for this is because the instantiate item method creates adjacent pages when the user changes views so as to aid fast loading. I handled my click events inside the instantiate item method so what is happening is that when the adjacent view is instantiated and the user clicks one of the list items in the current view, the adjacent view content is what is displayed. I thought to ask the appropriate way to handle events for multiple listviews in the viewpager.
thanks
Hi….nice posts.
I would like to add ListView on 1st Tab, Google Map on 2nd tab and so on. Different controls on different tabs. I modified your instantiateItem() to display ListView only on 1st tab. Trying to add Google map on 2nd tab. How to attach MapActivity to this 2nd Tab/pager? Pager doesn’t allow starting intent to MapView class. Any hints?
Thanks and regards
Like Sam said, can we add Google map to 2nd tab?
Hi, i’m asking if there is a method to animate the viewpager making it change the tab by code! THANKS!
I love you! good article