I am using the ViewPager consisting of 6 pages to display some data. I want to be able to call a method when the user is at position 0 and tries to swipe to the right (backwards), or at position 5 and tries to swipe to the left (forward), even though no more pages exist for these directions. Is there any way I can listen for these scenarios?
-
Hi all, I have used the code but the onSwipeOutLister method is not called in my activity even if I call the method. please see my question posted http://stackoverflow.com/questions/25889115/android-viewpager-detect-swipe-beyond-the-bounds – M.A.Murali Sep 17 '14 at 11:21
6 Answers
Extend ViewPager and override onInterceptTouchEvent()
like this:
public class CustomViewPager extends ViewPager {
float mStartDragX;
OnSwipeOutListener mListener;
public void setOnSwipeOutListener(OnSwipeOutListener listener) {
mListener = listener;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
float x = ev.getX();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mStartDragX = x;
break;
case MotionEvent.ACTION_MOVE:
if (mStartDragX < x && getCurrentItem() == 0) {
mListener.onSwipeOutAtStart();
} else if (mStartDragX > x && getCurrentItem() == getAdapter().getCount() - 1) {
mListener.onSwipeOutAtEnd();
}
break;
}
return super.onInterceptTouchEvent(ev);
}
public interface OnSwipeOutListener {
public void onSwipeOutAtStart();
public void onSwipeOutAtEnd();
}
}

- 6,575
- 3
- 39
- 59
-
I have created a class called CustomViewPager and implemented the method above. How do I communicate back with my activity when one of the If statement conditions are met? Is there some sort of way of setting up a listener or something in my activity using the ViewPager object? – Nicklas Nov 14 '12 at 12:47
-
I updated my answer. You just need to call `setOnSwipeOutListener()` in your activity. I didn't run this code, so it may need to make a few ajustments. – Flávio Faria Nov 14 '12 at 14:33
-
Hi all, I have used the code but the onSwipeOutLister method is not called in my activity even if I call the method. please see my question posted http://stackoverflow.com/questions/25889115/android-viewpager-detect-swipe-beyond-the-bounds – M.A.Murali Sep 17 '14 at 11:20
-
For me onInterceptTouchEvent not generating continuous MOVE event. Any suggestion here http://stackoverflow.com/q/28605921/2624806. – CoDe Feb 19 '15 at 13:04
-
@M.A.Murali Check my answer to see how to hook up your activity to this `CustomViewPager` - http://stackoverflow.com/a/31275349/1617737 – ban-geoengineering Jul 07 '15 at 17:23
-
Thanks a lot to @Flavio, although i had to do some changes to his code because the callbacks methods were firing twice, also I added code to check if there was any registered listener, to avoid app crashing when there is no listener registered. This is the code I used to make it work, with both onSwipeOutAtStart and onSwipeOutAtEnd:
public class CustomViewPager extends android.support.v4.view.ViewPager {
float mStartDragX;
OnSwipeOutListener mOnSwipeOutListener;
public CustomViewPager(Context context) {
super(context);
}
public CustomViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOnSwipeOutListener(OnSwipeOutListener listener) {
mOnSwipeOutListener = listener;
}
private void onSwipeOutAtStart() {
if (mOnSwipeOutListener!=null) {
mOnSwipeOutListener.onSwipeOutAtStart();
}
}
private void onSwipeOutAtEnd() {
if (mOnSwipeOutListener!=null) {
mOnSwipeOutListener.onSwipeOutAtEnd();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch(ev.getAction() & MotionEventCompat.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
mStartDragX = ev.getX();
break;
}
return super.onInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent ev){
if(getCurrentItem()==0 || getCurrentItem()==getAdapter().getCount()-1){
final int action = ev.getAction();
float x = ev.getX();
switch(action & MotionEventCompat.ACTION_MASK){
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (getCurrentItem()==0 && x>mStartDragX) {
onSwipeOutAtStart();
}
if (getCurrentItem()==getAdapter().getCount()-1 && x<mStartDragX){
onSwipeOutAtEnd();
}
break;
}
}else{
mStartDragX=0;
}
return super.onTouchEvent(ev);
}
public interface OnSwipeOutListener {
void onSwipeOutAtStart();
void onSwipeOutAtEnd();
}
}

- 1,408
- 15
- 28

- 3,777
- 4
- 30
- 49
-
3Works a treat (with only one callback for each swipe!). BTW, you may want to make your activity `implements CustomViewPager.OnSwipeOutListener` and, also in your activity, don't forget to call `myCustomViewPager.setOnSwipeOutListener(this);` on your CustomViewPager object. – ban-geoengineering Jul 07 '15 at 17:33
-
-
It is not work, setCurrentItem performed but not swipe, on MotionEvent.ACTION_UP it is not work but on MotionEvent.ACTION_MOVE swipe but not correctly. On activity I use setCurrentItem with thread and worked, I will add answer. – Kanan Jul 18 '23 at 09:58
-
Dear @Kanan, did you make your activity implement CustomViewPager.OnSwipeOutListener and in your activity, do you call myCustomViewPager.setOnSwipeOutListener(this); on your CustomViewPager object? – spacebiker Aug 20 '23 at 09:04
-
The answer from Flávio Faria doesn't work for me. The only event I get in onInterceptTouchEvent() is ACTION_DOWN event. So I override the onTouchEvent() method to get it work.
Here is the code. Note that I only have onSwipeOutAtEnd() in the listener. You can add your code to support swiping left on first vier.
public class CustomViewPager extends ViewPager {
float mStartDragX;
OnSwipeOutListener mListener;
public void setOnSwipeOutListener(OnSwipeOutListener listener) {
mListener = listener;
}
@Override
public boolean onTouchEvent(MotionEvent ev){
if(getCurrentItem()==getAdapter().getCount()-1){
final int action = ev.getAction();
float x = ev.getX();
switch(action & MotionEventCompat.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
mStartDragX = x;
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (x<mStartDragX){
mListener.onSwipeOutAtEnd();
}else{
mStartDragX = 0;
}
break;
}
}else{
mStartDragX=0;
}
return super.onTouchEvent(ev);
}
public interface OnSwipeOutListener {
public void onSwipeOutAtEnd();
}

- 343
- 5
- 17
-
You'll be receiving only `ACTION_DOWN` in `onInterceptTouchEvent()` if you return `true` from that method. – Flávio Faria Jan 06 '14 at 20:01
-
Hi all, I have used the code but the onSwipeOutLister method is not called in my activity even if I call the method. please see my question posted http://stackoverflow.com/questions/25889115/android-viewpager-detect-swipe-beyond-the-bounds – M.A.Murali Sep 17 '14 at 11:20
-
1I actually found out that receiving `move` depends on the contents of the pager. I used to add `LinearLayout` and I was not receiving the move. When I wrapped the layout in `ScrollView` then it started working - a bit more complex layout, though. – Boris Strandjev Nov 29 '14 at 09:19
-
How about setting an OnPageChangeListener on your ViewPager? Then you can modify your navigation arrows or whatever in the onPageScrolled.
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
updateNavigationArrows();
}
@Override
public void onPageScrollStateChanged(int state) {
}
});

- 191
- 2
- 4
-
5The method `setOnPageChangeListener()` is deprecated in newer SDKs and was replaced with `addOnPageChangeListener()`. – Leukipp Dec 16 '15 at 11:44
I wonder how it worked for others, it's not working for me.
onInterceptTouchEvent()
only takes ACTION_DOWN
event. While onTouchEvent()
only takes one event at a time either ACTION_DOWN
, ACTION_UP
and others.
I had to override both onInterceptTouchEvent()
and onTouchEvent()
to make it work properly. The ACTION_DOWN
of onInterceptTouchEvent
grabs initial X
point of touch, and OnTouchEvent
grabs final X2
point. Which I compared it to detect swipe direction.
Get initial X value of the touch:
float x1 = 0;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch(ev.getAction() & MotionEventCompat.ACTION_MASK){
case MotionEvent.ACTION_DOWN:
x1 = ev.getX();
break;
}
return super.onInterceptTouchEvent(ev);
}
From tjlian616's code, the onTouchEvent()
listens to ACTION_UP
and gets it's last X
Value.
While I've set my current item's value to be 0 to get swipe out at start listener. Compared it and add fired up the listener.
@Override
public boolean onTouchEvent(MotionEvent ev){
if(getCurrentItem()==0){
final int action = ev.getAction();
switch(action & MotionEventCompat.ACTION_MASK){
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mStartDragX = ev.getX();
if (x1<mStartDragX){
Log.i("TOUCH: ", "ACTION UP " + x1 + " : " + mStartDragX );
mListener.onSwipeOutAtStart();
}else{
Log.i("TOUCH ELSE : ", "ACTION UP " + x1 + " : " + mStartDragX );
mStartDragX = 0;
}
break;
}
}else{
mStartDragX=0;
}
return super.onTouchEvent(ev);
}

- 191
- 2
- 9
I used @spacebiker answer but It is not work, setCurrentItem performed but not swipe, on MotionEvent.ACTION_UP it is not work but on MotionEvent.ACTION_MOVE swipe but not correctly. On activity I use setCurrentItem with thread and worked.
public class ViewPagerFixed extends androidx.viewpager.widget.ViewPager {
float mStartDragX;
OnSwipeOutListener mOnSwipeOutListener;
public ViewPagerFixed(Context context) {
super(context);
}
public ViewPagerFixed(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setOnSwipeOutListener(OnSwipeOutListener listener) {
mOnSwipeOutListener = listener;
}
private void onSwipeOutAtStart() {
if (mOnSwipeOutListener != null) {
mOnSwipeOutListener.onSwipeOutAtStart();
}
}
private void onSwipeOutAtEnd() {
if (mOnSwipeOutListener != null) {
mOnSwipeOutListener.onSwipeOutAtEnd();
}
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if ((ev.getAction() & MotionEventCompat.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
mStartDragX = ev.getX();
}
try {
return super.onInterceptTouchEvent(ev);
} catch (IllegalArgumentException e) {
return false;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (getCurrentItem() == 0 || getCurrentItem() == getAdapter().getCount() - 1) {
float x = ev.getX();
if ((ev.getAction() & MotionEventCompat.ACTION_MASK) == MotionEvent.ACTION_UP) {
if (getCurrentItem() == 0 && x > mStartDragX) {
onSwipeOutAtStart();
}
if (getCurrentItem() == getAdapter().getCount() - 1 && x < mStartDragX) {
onSwipeOutAtEnd();
}
}
} else {
mStartDragX = 0;
}
return super.onTouchEvent(ev);
}
public interface OnSwipeOutListener {
void onSwipeOutAtStart();
void onSwipeOutAtEnd();
}
}
On Activity implements OnSwipeOutListener
public class ExapleActivity extends AppCompatActivity implements ViewPagerFixed.OnSwipeOutListener{
private ViewPagerFixed viewPager;
private WormDotsIndicator dot;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.example_layout);
viewPager = findViewById(R.id.view_pager);
dot = findViewById(R.id.dot);
ViewPagerAdapterUploadImage adapter = new ViewPagerAdapterUploadImage(this, this, viewPager);
viewPager.setAdapter(adapter);
dot.setViewPager(viewPager);
viewPager.setOnSwipeOutListener(this);
}
@Override
public void onSwipeOutAtStart() {
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.runOnUiThread(() -> {
viewPager.setCurrentItem(viewPager.getAdapter().getCount() - 1, true);
});
}).start();
}
@Override
public void onSwipeOutAtEnd() {
new Thread(() -> {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.runOnUiThread(() -> {
viewPager.setCurrentItem(0, true);
});
}).start();
}
}

- 203
- 1
- 15