04-08-2011 13:30
Google recently released a couple of Android applications where it is possible to scroll through views.This has been seen before in applications such as Youtube, but two things are different. One is the indication bar telling us what we are looking at, and what we can find, if we move right or left. This is a fast, minimalistic way for the user to see what he is looking at, and also a nice indication that you can scroll sideways, and what you will get if you do. The other way this differentiates itself from the previous implementations is that Google released a library as well as the source for all to use.
Only problem is, they didn’t release the indicator, so if you want your new application to fit in with the latest and greatest from Google you are stuck with making it yourself, or finding some of the other solutions out there. Screenshot here.
We have implemented an easy to use indicator View that closely follows the behavior of the Google+ indicator. Shown on the image is the indicator used to show consecutive dates.
You add the indicator to the layout is just as you would any other:
<com.zylinc.view.ViewPagerIndicator
android:id="@+id/indicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffeaeaea"
android:paddingLeft="5dp"
android:paddingRight="5dp" />
This gives you just the line containing the titles of the pages. It is up to you to style the indicator such that it fits in to your application with additional views. The layout on the screenshot can be found in the example application.
Now, some initialization is necessary before the indicator is fully operational. Your OnCreate might look something like this:
Running init on the indicator is mandatory, as it will not otherwise have the data it needs. Adding arrow images is optional (but generally a good idea).
Finally the callback is a simple method returning the title of the page at a given position. We have opted to extend the pager to do this, returning the date for that position:
While most of the view can be styled with normal view attributes the focused and unfocused text colors can be set programmatically using the setFocusedTextColor (int[3]) and setUnfocusedTextColor(int[3]) methods. They take an array containing the integer representation of rgb.
Just like the compatibility library, the ViewPagerIndicator is compatible with Android SDK version 4 and up.
Download source and example code - here.
Mark Gjøl is an M.Sc from The Technical University of Denmark, the creator of the Android gallery Floating Image, and works with Android, Windows and Tomcat applications.
Comment by Julien | 19-08-2011
Thank you for the release. What is the licence of the source?
Comment by Mark Gjøl | 07-09-2011
Hi Julien
The source is licensed as Public Domain, so you can use it for anything you like, no restrictions. This also means that there is no warranty associated with this code.
Best regards
Mark Gjøl
Comment by Pramod | 09-09-2011
How to create 3X3 array of images in viewpager like gridview which scrolls horizontally.
Comment by Mark Gjøl | 09-09-2011
Hi Pramod,
The scope of this post does not cover the use of the ViewPager, but a short answer would be to simply make a gridView in the fragments you show in the ViewPager. If this is not what you are looking for, I suggest you post your question at http://stackoverflow.com as that site is dedicated to answering all kinds of questions.
Best regards,
Mark Gjøl
Comment by Ben | 15-09-2011
absolutely brilliant. i was going to implement one myself, but you saved me a bunch of time. thanks!
Comment by Thorsten Dittmar | 19-09-2011
Hi,
first of all, thanks for this great release. This is what I've been looking for.
There seem to be minor bugs, which I hope you can fix more quickly than I:
I have a limited set of pages I want to display. When I set the "startup page" to the first page (index 0), there's no caption for the previous page (which is correct), but the arrow image is still showing. When I swipe right and then left, both caption and image are gone, which would be correct.
When I set the "startup page" to the last page, both caption and arrow for the next page are showing. When I try to navigate to the right, they disappear.
I hope you can fix this and release a new version?
Thanks,
Thorsten
Comment by Mark Gjøl | 19-09-2011
Hello Thorsten,
We have uploaded a new version that should resolve your issues.
However, I could not reproduce all of them. Some of the errors sound like you are initializing the indicator with the wrong start position (I got the same error at first when I tried). Please make sure, that you are calling init() with the same position as you are setting in viewPager.setCurrentItem().
Best regards,
Mark Gjøl
Comment by Thorsten Dittmar | 19-09-2011
Hi Mark,
wow, that was fast! The issues are solved, thank you so much!
Comment by MOhan | 20-09-2011
Hi
Firstly thanks so much for the example. I was able to run it. I am new to android and graphics like these. I am trying to understand is how does the text above move as I scroll my screen horizontally. Which part of the code is responsible for that or it the behavior of the ViewPager itself ?
You comments will be greatly appreciated.
Comment by JH | 05-10-2011
Hello sorry how do I set different layout for different page when swype
Comment by Tos | 20-10-2011
Hello, nice job !
I was able to implement it without problems in my project.
However there is one issue: when the phone is rotated the ViewPager jumps to the first page (and does not stay on the current page). A small issue, I agree.
Tos
Answer to JH: just use diffent xml files. Eg page0.xml, page1.xml, etc
Comment by Mark Gjøl | 01-11-2011
@MOhan - The ViewPager passes an offset to the indicator which it uses to position the text. The text itself is simply TextViews being moved around.
@Tos - I do not get this behaviour. Have you found the error?
Comment by Tos | 02-11-2011
Mark, I confirm that observe the said behaviour in your sample project ! ( ViewPagerIndicator-src.zip )
You can try it on the emulator: change the emulator orientation by typing Ctr-F11.
Being more accurate: when rotating the phone, it is only the indicator which jumps back to the first one (leftmost). The page iself correctly stays where it is.
I haven't solved it yet. Maybe is is simply a matter of overrinding onSaveInstanceState() and onRestoreInstanceState() with the appropriate Bundle.
Comment by Mark Gjøl | 03-11-2011
Tos - Ok, I get that. I have uploaded a new version that fixes this issue. The problem is that the ViewPager doesn't notify that it has changed page when it restores it's instance state (but rather says what it's initialized to). If you want to merge it yourself just add these two blocks:
@Override
protected Parcelable onSaveInstanceState() {
Parcelable state = super.onSaveInstanceState();
Bundle b = new Bundle();
b.putInt("current", this.mCurItem);
b.putParcelable("viewstate", state);
return b;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
super.onRestoreInstanceState(((Bundle)state).getParcelable("viewstate"));
mCurItem = ((Bundle)state).getInt("current", mCurItem);
this.setText(mCurItem - 1);
this.updateArrows(mCurItem);
this.invalidate();
}
And also remove the line:
mCurItem = position;
from the OnPageSelected(int position) method.
Comment by Tos | 03-11-2011
Hi Mark,
thanks for the update but it still doesn't work. You also need to modifiy mCurItem at some point otherwise it will stay at zero forever.
You need to add the following line in method onPageScrolled( ):
mCurItem = position; // NEW !
It now works with me...
Comment by Jamie | 04-11-2011
Hi!
When I use the ViewPager and ViewPagerIndicator I find that my Adapter becomes null when the Activity orientation changes.
The lastest changes made to keep the state of pages during rotation seems to break because onRestoreInstanceState(...) is called before onResume(..) is able create my Adapters again.
Instead of including the changes I simply added these two lines in onPageSelected(..) :
setText(position - 1);
updateArrows(position);
Comment by Mark Gjøl | 07-11-2011
Hi Tos, Apologies. I think this is the change made in the uploaded code, but not in the example I provided. After changing the sample a couple of times I guess I lost track of the changes. :)
@Jamie: I guess it depends on how you do your implementation, but most things should be created in OnCreate, and then it's not a problem.
If you do it your way however, the ViewPager probably loads it's instanceState before it executes onPageSelected, and the correct page is returned.
Comment by Tos | 07-11-2011
Oh, I see... Nice job, thanks !
Comment by Anu | 10-11-2011
It says import com.jakewharton cannot be be resolved. Please help
Comment by Mark Gjøl | 10-11-2011
Hi Anu, This is from a similar project ( https://github.com/JakeWharton/Android-ViewPagerIndicator ) but not this one. I suggest you either ask at that site, or you use our implementation.
Comment by Tos | 08-12-2011
Hi Mark,
it's me again.. I am wondering if you have any thoughts on the following problem; On one of the pages, I have an ImageView on which I attach a touch listener with setOnTouchListener(). I return true in this listener (meaning that the listener has consumed the event). However, when I touch the ImageView and move horizontally, the ViewPager moves to another page. I'd like to move to another page only when I touch outside of the ImageView.
Do you have an idea of what's happening ?
Tos
Comment by Mark Gjøl | 13-12-2011
Hi Tos, I'm sorry, but I don't know why this happens. I recommend you ask this question at http://stackoverflow.com .
Good luck,
- Mark
Comment by Tos | 13-12-2011
I did ask actually on Stack Overflow a few weeks ago... without an answer! Right now I'm using a workaround. Not exactly what I wanted but it is fine. I'll keep it that way. Thank you. Tos.
Comment by Azam Baqa | 30-12-2011
Hi Mark
This is great. I have a TextView on all pages in the ViewPager. I want to hide/show it on all pages on a button click. Wen I click the button, it applies the change after 2 pages from the current. If I scroll pages back and forth then I see the change on the current page. Any idea? A detailed question is at http://stackoverflow.com/questions/8634778/how-to-refresh-current-view-in-viewpager
Thanks
Comment by Mark Gjøl | 02-01-2012
Hello Azam.
I have answered your question on stackoverflow.
Best regards,
- Mark
Comment by Ali | 22-01-2012
How can I add title ?
@Override
public String getTitle(int pos){
String[] ListItems = new String[]{"Test1","Test2"};
return ListItems.toString();
}
It's not working for me.
Comment by James | 23-01-2012
Check please:
http://stackoverflow.com/questions/8965591/represent-items-on-fragmentpageradapter
Comment by Mark Gjøl | 23-01-2012
@Ali: You should probably define your array somewhere else, but the issue is that you are returning the toString() on your array (which returns where in memory it is located). Instead you should return:
ListItems.get(pos);
For future comments, please try to only post comments that are directly related to the indicator described in this post, and not just general questions about viewpagers (you can go to stackoverflow for that).
Thank you.
Comment by Raul | 25-03-2012
How can I add your class to my project? So far I've tried creating a package called com.zylinc.view and Inside I add the ViewPagerIndicator from your code and somehow I end up with a class not found exception.
Of course I used the xml you posted here in your article.
Thanks a lot for your help!
Comment by Mark Gjøl | 21-05-2012
Hi Raul,
Just add the source file, and it should work fine.
Comment by ClerkMaxwell | 22-05-2012
It's great,THX.But if I want to do this:
A -> B
B -> C
C -> A
How can I do?
Comment by Mark Gjøl | 23-05-2012
@ClerkMaxwell, This issue has been addressed here: http://stackoverflow.com/questions/7546224/viewpager-as-a-circular-queue-wrapping
It seems it is not supported directly, but can be simulated with a small hack.
Comment by Aditya | 27-05-2012
I am using your code to put list of strings but i am unable to use it. Can you please help in which instead of date i can give 5 names of cities.
Comment by Mark Gjøl | 30-05-2012
Hi Aditya,
In the PageInfoProvider you have created change the getTitle(int pos) method to return your city names rather than dates. You could for instance just create an array with five city names in it with each city representing a pos.
Comment by Swapnil | 05-06-2012
hi mark,
nice tutorial but i am getting a bug can u tell me how to resolve it...the log is as follows
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.zylinc.view/com.zylinc.view.ViewPagerIndicatorActivity}: java.lang.ClassNotFoundException: com.zylinc.view.ViewPagerIndicatorActivity in loader dalvik.system.PathClassLoader[/data/app/com.zylinc.view-2.apk]
Comment by Mark Gjøl | 06-06-2012
Hi Swapnil,
This bug usually appears when the runtime can't find the class. Are you including this as a library or have you just added the file to your project?
If it's a library then maybe it's copied to the phone?
If you just included the code, try cleaning your project.
Comment by Swapnil | 19-06-2012
hi mark,
amazing work appreciated.... thanks mate for wonderful tutorial.
Comment by Shahzad Imam | 05-07-2012
That was really awesome 4 me...Worked perfectly....Found after 1 day of rigorous search
Comment by Murilo Angelo | 09-07-2012
I am facing problems when starting the indicator, what I do, the only thing that appears is going to build the project patcher and I do not know what to do
Comment by Mark Gjøl | 10-07-2012
Hello Murilo Angelo,
Could you please elaborate on what you are doing, and what error you are getting?
Thank you.
Comment by Murilo Angelo | 12-07-2012
I'm sorry I expressed myself badly, but managed to solve the problem that previously had. I managed to do all of your implementation, but I'm with a doubt in ITEMFRAGMENTE that extends LISTFRAGMENT, so I could see, first I want to know how I would like to go through the screens for each of them a different layout, because the way here it is, everyone has the same list with the names of countries, for example, how would I do for each view (list fragment) show a list of different names?
Comment by Abhinov | 13-08-2012
Hai i just downloaded your source code i got force close should i need to add the libraries if i need to add tell me how to add it i am struck with viewpager from one wek plz help me out of this
Comment by Mark Gjøl | 14-08-2012
Hi Murilo, sorry for the late answer (summer and all)... In the pagerAdapter you have full control of what is shown on each page. Simply return a different kind of fragment for a different position.
Comment by Mark Gjøl | 14-08-2012
Hi Abhinov, You should add the support library as described here: http://developer.android.com/tools/extras/support-library.html
Comment by Vincent | 17-08-2012
This is GREAT! I am experiencing one issue, that I can not get resolved. When I scroll to the very last page, then scroll back 1 the indicator text does not change to the SELECT color, it stays the out of focused. It goes back to correct if I go back and then forward again, but going to the last visible page and going back seems to not reset the color??
Any ideas?
Comment by Mark Gjøl | 21-08-2012
Hi Vincent, That sounds very odd (and seems to work here). I'm afraid I can't do much without trying out your code myself...
Comment by Andy | 24-12-2012
Hi,
Can you please tell me how to draw dot indicator into bottom of the screen, this is the requirement for my project.
Second, current page should be highlighted as well.
Please help me I want to use your code and how to proceed ?
Thanks in Advance,
Andy
Comment by Mark Gjøl | 02-01-2013
Hi Andy, Our code is not really suitable for your needs in this instance. However, if you go to http://viewpagerindicator.com then you will find a similar project that among a lot of other visualizations has the kind of dot indicator you are looking for.