How to Do Circular Scrolling on Viewpager

How to do circular scrolling on ViewPager?

Ok, I have an answer. It was actually easier than I expected, but it does take some trickery. First, let me begin with the set up. Lets say, for example, you have three pages (A-B-C) that you are scrolling through in your ViewPager. And you want to set it up so that if you continue scrolling on C (pg. 3), it goes to A (pg. 1) and if you scrolled backwards on A (pg. 1) it goes to C (pg. 3).

I am not saying my solution is the best, but it works and I do not see any issues. First, you have to create two "fake" pages. The fake pages represent the first and last pages of your ViewPager. The next thing you will need is to set up an onPageChangeListener(), and use the method onPageSelected(). The reason why you need the fake pages is because onPageSelected() only registers after you have moved (swiped). In other words, without this method the end user would have to scroll to page 2 and back to page 1 to receive a hit on page 1, which also means that page 1 would be skipped depending on your code logic.

The setup is really the entire answer. Once you have your fake pages, it is just a matter of using setCurrentItem() inside the necessary method.

Here is how my code looks. Be sure to place this inside your public Object instantiateItem(final ViewGroup container, final int position) method, just before you return your view inside of your container.

((ViewPager) container).setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Log.d(TAG, "onPageSelected() :: " + "position: " + position);

// skip fake page (first), go to last page
if (position == 0) {
((ViewPager) container).setCurrentItem(118, false);
}

// skip fake page (last), go to first page
if (position == 119) {
((ViewPager) container).setCurrentItem(1, false); //notice how this jumps to position 1, and not position 0. Position 0 is the fake page!
}

}

That's it, it does the trick! The only other thing to do is start your ViewPager on position 1 (which is the second page: fake page = pg 1, my real starting page = pg 2). Now, every time I scroll to the fake page, I redirect it backwards to the last real page. And every time I scroll forward to the last fake page, I redirect it forwards to the real starting page (pg 2).

Also, do not try to put any code in onPageScrollStateChanged. That method is bizarre, it seems that the state value is uncontrollable. It constantly jumps from one state to another. Even without scrolling. That is just a tip I picked up.

Circular ViewPager for continuous scrolling

Just implement the ViePager.OnPageChangeListener:

YOUR_VIEWPAGER.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
currentPage = position;
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// not needed
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_IDLE) {
int pageCount = pages.size();

if (currentPage == 0){
YOUR_VIEWPAGER.setCurrentItem(pageCount-2,false);
} else if (currentPage == pageCount-1){
YOUR_VIEWPAGER.setCurrentItem(1,false);
}
}
}
});

Circular scrolling with View Pager

Forget about ViewPager it's expensive, views is everything. You need three inflated views
let's say v1,v2,v3

I work with your provide git sample project, replace your HorizontalPaging with xml

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="300dp"
android:id="@+id/scroller"
app:layout_constraintEnd_toEndOf="parent"
android:fillViewport="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">

<ImageView
android:id="@+id/v1"
android:layout_width="match_parent"
android:layout_height="300dp"
android:contentDescription="@null"
android:src="@drawable/slider_topup" />

<ImageView
android:id="@+id/v2"
android:layout_width="match_parent"
android:layout_height="300dp"
android:contentDescription="@null"
android:src="@drawable/slider_balance" />

<ImageView
android:id="@+id/v3"
android:layout_width="match_parent"
android:layout_height="300dp"
android:contentDescription="@null"
android:src="@drawable/slider_bundles" />

</RelativeLayout>

and add code to your onCreate

final View v1 = findViewById(R.id.v1);
final View v2 = findViewById(R.id.v2);
final View v3 = findViewById(R.id.v3);

//set initial state keep it sync with wheel at start
v1.setX(0);
v2.setX(screenSize);
v3.setX(2*screenSize);

circle.setOnAngleChangeListener(new NowCircle.OnAngleChangeListener() {
@Override
public void onAngleChange(float delta) {
float v1x = v1.getX() + (oneDegree * delta);
float v2x = v2.getX() + (oneDegree * delta);
float v3x = v3.getX() + (oneDegree * delta);

Log.d("dd","delta:"+delta+", v1x:"+v1x+", v2x:"+v2x +", v3x:"+v3x);

v1.setX(v1x);
v2.setX(v2x);
v3.setX(v3x);

if(delta > 0){

if (v1x >= 0 && v1x <= screenSize) {
v3.setX(-screenSize+v1x);
//update data here
}else if (v3x >= 0 && v3x <= screenSize){
v2.setX(-screenSize+v3x);
//update data here
}else {
v1.setX(-screenSize+v2x);
//update data here
}
}else {
if (v3x <= 0 && v3x >= -screenSize) {
v1.setX(screenSize+v3x);
//update data here
}else if(v1x <= 0 && v1x >= -screenSize){
v2.setX(screenSize+v1x);
//update data here
}else {
v3.setX(screenSize+v2x);
//update data here
}
}
}
});

animation is achieved, working fine.

Sample Image

You need to improve this and bind data with your custom views and create one separate manage class. I put my time into this. you know :)

ViewPager as a circular queue / wrapping

I've implemented a ViewPager/PagerAdapter that can allow for pseudo-infinite paging behaviour. It works by specifying a very large number as the actual count, but maps them to the actual range of the dataset/pageset. It offsets the beginning by a large number also so that you can immediately scroll to the left from the 'first' page.

It doesn't work so well once you get to 1,000,000th page (you will see graphical glitches when scrolling), but this is typically not a real-world use-case. I could fix this by resetting the count to a lower number once in a while, but I will leave it how it is for now.

The InfinitePagerAdapter wraps an existing ViewPager, and so the usage is quite transparent. The InfiniteViewPager does does a bit of work to make sure you can potentially scroll to the left and right many times.

https://github.com/antonyt/InfiniteViewPager

how to create circular viewpager?

Circular ViewPager is possible.
With the help of ViewPager as a circular queue / wrapping this link have coded like this. Hope it helps what you needed.

The CircluarPagerAdapter class:

>

 public class CircularPagerAdapter extends PagerAdapter{

private int[] pageIDsArray;
private int count;

public CircularPagerAdapter(final ViewPager pager, int... pageIDs) {
super();
int actualNoOfIDs = pageIDs.length;
count = actualNoOfIDs + 2;
pageIDsArray = new int[count];
for (int i = 0; i < actualNoOfIDs; i++) {
pageIDsArray[i + 1] = pageIDs[i];
}
pageIDsArray[0] = pageIDs[actualNoOfIDs - 1];
pageIDsArray[count - 1] = pageIDs[0];

pager.setOnPageChangeListener(new OnPageChangeListener() {

public void onPageSelected(int position) {
int pageCount = getCount();
if (position == 0){
pager.setCurrentItem(pageCount-2,false);
} else if (position == pageCount-1){
pager.setCurrentItem(1,false);
}
}

public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// TODO Auto-generated method stub
}

public void onPageScrollStateChanged(int state) {
// TODO Auto-generated method stub
}
});
}

public int getCount() {
return count;
}

public Object instantiateItem(View container, int position) {
LayoutInflater inflater = (LayoutInflater) container.getContext()
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int pageId = pageIDsArray[position];
View view = inflater.inflate(pageId, null);
((ViewPager) container).addView(view, 0);
return view;
}

@Override
public void destroyItem(View container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}

@Override
public void finishUpdate(View container) {
// TODO Auto-generated method stub
}

@Override
public boolean isViewFromObject(View view, Object object) {
return view == ((View) object);
}

@Override
public void restoreState(Parcelable state, ClassLoader loader) {
// TODO Auto-generated method stub
}

@Override
public Parcelable saveState() {
// TODO Auto-generated method stub
return null;
}

@Override
public void startUpdate(View container) {
// TODO Auto-generated method stub
}
}

and this is your main class:

>

public class MainActivity extends Activity {

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ViewPager myPager = (ViewPager) findViewById(R.id.conpageslider);
PagerAdapter adapter = new CircularPagerAdapter(myPager, new int[]{R.layout.first_activity, R.layout.second_activity, R.layout.third_activity});
myPager.setAdapter(adapter);
myPager.setCurrentItem(3);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

}

How to set the Adapter for the circular Scroll-able tab

You should set adapter like this

MyAdapter adapter=new MyAdapter(fragmentManager);
InfinitePagerAdapter myAdapter= new InfinitePagerAdapter(adapter);
pager.setAdapter(myAdapter);

Also in your adapter change this code

from this

@Override
public int getCount() {
return Integer.MAX_VALUE;
}

to

@Override
public int getCount() {
return 5;
}



Related Topics



Leave a reply



Submit