I would like to implement a ViewPager which uses Fragments and can be swiped in a curcular motion e.g. Page (A<-->B<-->C<-->A). I have read a couple of posts on how this is done, e.g. returning a fake count of how many elements there are and setting the position at the start in the middle. how to create circular viewpager?
These all seem to be based of a PagerAdapter. When I try to do a similar thing while extending FragmentPagerAdapter, as soon as I return a fakeCount of pages I get an exception when I Swipe through my Fragments, I only have 2 Fragments. Exception: java.lang.IllegalStateException: Can't change tag of fragment.
I think this is caused as the FragmentManager thinks I am in position 2 but position 2 points to the fragment at position 0. Does anyone know how I can avoid this? I am thinking I should experiment with extending Fragmentmanager. Any examples or help with this would be greatly appreciated.
I know it is a bit late but this is how it worked for me:
I needed a circular swipe between 3 fragments, so I made those 3 and two more virtual to help me implement the page looping:
And two more virtual fragments that enabled me to swipe left from the first and right from the last. The first virtual inflates the same layout as the last actual and the last virtual the same layout as the first actual:
My Adapter:
And my page listener I used the onPageScrollStateChanged to set the correct page and implement the loop:
And in the end:
Hope I helped
I have a project in the GitHub with some widgets I've created. Here it its:
https://github.com/CyberEagle/AndroidWidgets
In the following package, there are the adapters to be used with the CircularViewPager: https://github.com/CyberEagle/AndroidWidgets/tree/master/src/main/java/br/com/cybereagle/androidwidgets/adapter
First, you will use CircularViewPager instead of ViewPager in your layout. The CircularViewPager is here: https://github.com/CyberEagle/AndroidWidgets/blob/master/src/main/java/br/com/cybereagle/androidwidgets/view/CircularViewPager.java
This ViewPager expects a WrapperCircularPagerAdapter, instead of a PagerAdapter. This wrapper is used to trick the ViewPager, making it to think there are a lot of items in the ViewPager, but it actually repeat your items to make the circular effect. So, instead of implementing either PagerAdapter, FragmentPagerAdapter or FragmentStatePagerAdapter, you will implement either CircularFragmentPagerAdapter, CircularFragmentStatePagerAdapter or CircularPagerAdapter. Then, you will wrap your adapter with the WrapperCircularPagerAdapter and set the wrapper in the CircularViewPager, instead of your adapter. Also, when it's time to notify dataset changed, you will call the notifyDatasetChanged() in the wrapper.
When implementing one of the circular adapter, you will notice that instead of implementing instantiateItem, you will have to implement instantiateVirtualItem. For the fragment's pager adapter, you will implement getVirtualItem instead of getItem. That is because I've created the concept of virtual items.
To make it clear, imagine a view pager with 4 items, giving that each item represents a music. When you go all the way to left, you will see the 4th item in the left of the first. Actually, it's a whole new item, but it's linked to the virtual item that represents the 4th music.
Another example: imagine there's only one music now. You will see the same music on the left and on the right. There're 3 items at a time, but only one virtual item.
So, as explained, the Wrapper is tricking the ViewPager, making it think that there are a lot of items. To make it more difficult for the user to reach one of the ends of the ViewPager (it'd take a long time anyway), everytime a change happens to the dataset, the ViewPager goes to the same virtual item, but to one of the real items near the middle.
One more important thing is that the CircularViewPager has the method setCurrentVirtualItem. This method calculates which real item is the nearest desired virtual item and then it uses the setCurrentItem to set it. You have also the option to use the getCurrentVirtualItem, that will return the index of the current virtual item. Notice that if you use getCurrentItem, you'll get a large index.
Well, this is it. I'm sorry for the lack of documentation of the project. I'm planning document it soon. I'm also planning to remove the need for the wrapper. Feel free to copy the code (respecting the Apache 2.0 license), to fork or even contribute to it.