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?
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();
}
}
setOnSwipeOutListener()
in your activity. I didn't run this code, so it may need to make a few ajustments. –
Hassiehassin CustomViewPager
- https://mcmap.net/q/57670/-android-viewpager-detect-swipe-beyond-the-bounds –
Metonym 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();
}
}
implements CustomViewPager.OnSwipeOutListener
and, also in your activity, don't forget to call myCustomViewPager.setOnSwipeOutListener(this);
on your CustomViewPager object. –
Metonym 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();
}
ACTION_DOWN
in onInterceptTouchEvent()
if you return true
from that method. –
Hassiehassin 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. –
Claybourne 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) {
}
});
setOnPageChangeListener()
is deprecated in newer SDKs and was replaced with addOnPageChangeListener()
. –
Tanah 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);
}
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();
}
}
© 2022 - 2024 — McMap. All rights reserved.