Viewpager Detect When User Is Trying to Swipe Out of Bounds

ViewPager detect when user is trying to swipe out of bounds

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();
}

}

Detect swiping out of bounds in Android's ViewPager2

I figured out a (slighly hacky) solution while I was typing this question.

It is based on the observation that the state SCROLL_STATE_SETTLING is only reached when the viewpager really settles on a new page. If there is only fruitless dragging on the first or last page then only the states SCROLL_STATE_DRAGGING and finally SCROLL_STATE_IDLE are passed.

viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {

private boolean settled = false;

@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
if (state == SCROLL_STATE_DRAGGING) {
settled = false;
}
if (state == SCROLL_STATE_SETTLING) {
settled = true;
}
if (state == SCROLL_STATE_IDLE && !settled) {
doYourOutOfBoundsStuff();
}
}
});

I'm not entirely happy, but this is the best I came across so far.

ViewPager disable swiping to a certain direction

I'm not sure this is exactly what you need:
I needed a viewpager for a wizard with a max page that the user can't pass it.

At the end the solution was in the adapter.
I changed the count of the PagerAdapter and this way blocks the user from passing the max page:

@Override
public int getCount() {
return mProgress; //max page + 1
}

When the user progresses to the next page:

private void setWizardProgress(int progress) {
if(progress > mProgress) {
mProgress = progress;
mWizardPagerAdapter.notifyDataSetChanged();
}
}

This way when the user is at max page he can't scroll to the right.

Disable viewpager when touching/dragging certain view

I managed to make it work using the function parent.requestDisallowInterceptTouchEvent(true); being placed inside the child view onTouchEvent(). This way the View does not allow none of his parents to interecpt his touch events in case a scroll happened and was to be handled by the ViewPager.

However in my case I had a ViewPager with a draggable custom views inside it which I wanted to move without that the ViewPager changes page.

My solution in terms of code: (Kotlin)

view.setOnTouchListener { v, event ->
parent.requestDisallowInterceptTouchEvent(true);
//Drag and drop handling is here and the rest of the event logic
}

I hope this will help you as well.

how to do an event when i swipe from fragment to the other

Use ViewPager.OnPageChangeListener of your view pager to detect swipe OR implement custom view pager see this

ADD THIS

mViewPager.setOnPageChangeListener(new OnPageChangeListener() {

@Override
public void onPageSelected(int arg0) {
// TODO Auto-generated method stub

//DO THINGS HERE

}

@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub

}

@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub

}
});

How to disable swiping in specific direction in ViewPager2

I found a listener which can listen when the user tries to swipe, it'll then check the current page, if it's the first page, disable the user input else enable it as it was by default.

Here's the code snippet for that

In Java:

pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);

if (state == SCROLL_STATE_DRAGGING && pager.getCurrentItem() == 0) {
pager.setUserInputEnabled(false);
} else {
pager.setUserInputEnabled(true);
}
}
});

In Kotlin:

viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)

viewPager.isUserInputEnabled = !(state == SCROLL_STATE_DRAGGING && viewPager.currentItem == 0)
}
})

Since my scenario was of 2 pages only, checking the page number would be good for me, but in case we have more than 2 pages and we need to disable the swipe in one particular direction, we may use onPageScrolled(int position, float positionOffset, int positionOffsetPixels) listener of viewpager2 and handle the desired scenario according to the positive or negative values of position and positionOffset.

Vertical ViewPager and Android Pie Inconsistent Behavior with Swipe Gesture

After spending hell amount of time on SO, trying many GitHub
libraries and waiting for someone to respond on the bounty,
then I came up with below solutions and hope that it helps whoever needs it.

At first, this question got my attention and I think most of the answers over there are helpful, hence I upvoted them.
The main answer which helped me are link-1 and link-2.

Even though I have to make a few minor changes to ignore horizontal swipe
fling events.

Please do try this code and provide your feedback for any further improvements, thanks in advance. Happy Coding :)

import android.content.Context;
import android.support.v4.view.MotionEventCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class VerticalViewPager extends ViewPager {
float x = 0;
float mStartDragX = 0;
private static final float SWIPE_X_MIN_THRESHOLD = 50; // Decide this magical nuber as per your requirement

public VerticalViewPager(Context context) {
super(context);
init();
}

public VerticalViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

private void init() {
// The majority of the magic happens here
setPageTransformer(true, new VerticalPageTransformer());
// The easiest way to get rid of the overscroll drawing that happens on the left and right
setOverScrollMode(OVER_SCROLL_NEVER);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
if (getAdapter() != null) {
if (getCurrentItem() >= 0 || getCurrentItem() < getAdapter().getCount()) {
swapXY(event);
final int action = event.getAction();
switch (action & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
mStartDragX = event.getX();
if (x < mStartDragX
&& (mStartDragX - x > SWIPE_X_MIN_THRESHOLD)
&& getCurrentItem() > 0) {
Log.i("VerticalViewPager", "down " + x + " : " + mStartDragX + " : " + (mStartDragX - x));
setCurrentItem(getCurrentItem() - 1, true);
return true;
} else if (x > mStartDragX
&& (x - mStartDragX > SWIPE_X_MIN_THRESHOLD)
&& getCurrentItem() < getAdapter().getCount() - 1) {
Log.i("VerticalViewPager", "up " + x + " : " + mStartDragX + " : " + (x - mStartDragX));
mStartDragX = 0;
setCurrentItem(getCurrentItem() + 1, true);
return true;
}
break;
}
} else {
mStartDragX = 0;
}
swapXY(event);
return super.onTouchEvent(swapXY(event));
}
return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
boolean intercepted = super.onInterceptTouchEvent(swapXY(event));
switch (event.getAction() & MotionEventCompat.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
x = event.getX();
break;
}
swapXY(event); // return touch coordinates to original reference frame for any child views
return intercepted;
}

/**
* Swaps the X and Y coordinates of your touch event.
*/
private MotionEvent swapXY(MotionEvent ev) {
float width = getWidth();
float height = getHeight();

float newX = (ev.getY() / height) * width;
float newY = (ev.getX() / width) * height;

ev.setLocation(newX, newY);

return ev;
}

private class VerticalPageTransformer implements PageTransformer {
@Override
public void transformPage(View view, float position) {

if (position < -1) { // [-Infinity,-1)
// This page is way off-screen to the left.
view.setAlpha(0);

} else if (position <= 1) { // [-1,1]
view.setAlpha(1);

// Counteract the default slide transition
view.setTranslationX(view.getWidth() * -position);

//set Y position to swipe in from top
float yPosition = position * view.getHeight();
view.setTranslationY(yPosition);

} else { // (1,+Infinity]
// This page is way off-screen to the right.
view.setAlpha(0);
}
}
}
}


Related Topics



Leave a reply



Submit