34

I am using ViewPager (support library). I want to know every time the ViewPager change the visible page, it is scrolling left or right.

Please give me a solution. Any recommend is welcome also.

Thanks

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Nguyen Minh Binh
  • 23,891
  • 30
  • 115
  • 165

15 Answers15

44

set setOnPageChangeListener to your ViewPager

keep a variable global as

private int lastPosition = 0;

and in

@Override
public void onPageSelected(int arg0) {
    if (lastPosition > position) {
         System.out.println("Left");
      }else if (lastPosition < position) {
         System.out.println("Right");
      }
      lastPosition = position;
}
ashishdhiman2007
  • 807
  • 2
  • 13
  • 28
Mohsin Naeem
  • 12,542
  • 3
  • 39
  • 53
  • 13
    but it give result once screen get scrolled completely...is there any way to as start scrolling? – CoDe Sep 16 '14 at 13:01
  • check my answer, it may not be the perfect solution but it's a start ;) – GuilhE Oct 31 '14 at 14:43
  • 1
    `setOnPageChangeListener` is deprecated now, use `ViewPager.addOnPageChangeListener` instead. – T-D Jun 06 '17 at 18:30
  • I tried all the solutions below and no one was working in my case. Good and simple solution. Nice job. – Nick Zisis Jun 27 '17 at 10:13
  • 1
    whats lastPage here? Is that supposed to be declared somewhere in this method. – Sdr Jan 16 '18 at 21:52
  • @CoDe onPageScrollStateChanged provides different states:- SCROLL_STATE_IDLE,SCROLL_STATE_DRAGGING, SCROLL_STATE_SETTLING. More :https://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html#onPageScrollStateChanged(int) – ashishdhiman2007 Jul 03 '19 at 10:35
43

It's not a perfect solution but here's a way to check the swipe direction when you start swiping:

new ViewPager.OnPageChangeListener() {

            private static final float thresholdOffset = 0.5f;
            private boolean scrollStarted, checkDirection;

            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                if (checkDirection) {
                    if (thresholdOffset > positionOffset) {
                        Log.i(C.TAG, "going left");
                    } else {
                        Log.i(C.TAG, "going right");
                    }
                    checkDirection = false;
                }
            }

            @Override
            public void onPageSelected(int position) {}

            @Override
            public void onPageScrollStateChanged(int state) {
                if (!scrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING) {
                    scrollStarted = true;
                    checkDirection = true;
                } else {
                    scrollStarted = false;
                }
            }
        });


EDIT: there's a more elegant approach that involves using a ViewPager.PageTransformer and checking it's position intervals:

...
myViewPager.setPageTransformer(true, new PageTransformer());
...

public class PageTransformer implements ViewPager.PageTransformer {
    public void transformPage(View view, float position) {

        if (position < -1) { 
            // [-00,-1): the page is way off-screen to the left.
        } else if (position <= 1) { 
            // [-1,1]: the page is "centered"
        } else { 
            // (1,+00]: the page is way off-screen to the right.           
        }
    }
}

You can learn more from: Using ViewPager for Screen Slides

GuilhE
  • 11,591
  • 16
  • 75
  • 116
  • how can i ctrl the left most click & the right most click? – Partha Chakraborty Apr 14 '15 at 12:02
  • Can you explain it better? – GuilhE May 08 '15 at 09:53
  • Very good response, it worked for me perfectly. In my case I needed to start an activity in the swipe gesture on the last page of ViewPager. if (position == fragmentPagerAdapter.getCount == () - 1) {      Intent intent = new Intent (Activity1.this, Activity2.class);      startActivity (intent);      Finish (); } – GFPF May 22 '15 at 16:21
  • The two solutions work well, if you have Build.VERSION.SDK_INT < 11 you have to use the first one, an in this one a have change a little bit the solution. I put: if (checkDirection) { if (positionOffset != 0) if (thresholdOffset > positionOffset) { Log.i(C.TAG, "going left"); } else { Log.i(C.TAG, "going right"); } checkDirection = false; } – Jachumbelechao Unto Mantekilla May 26 '15 at 08:54
  • 1
    `transformPage` must `@Override` as `ViewPager.PageTransformer` has abstract method `transformPage` – melvynkim Jun 20 '15 at 18:43
  • 1
    @melvkim When it was first introduced in JDK 1.5, Override was only applicable to methods defined in a superclass, and not in a supertype. That is, it originally applied to overriding methods in a base class, but not to implementing methods defined in an interface. This was changed in JDK 7, and now Override can be applied to both. So the answer: we should use it, it's a good practice, but we don't have to. This code and Android example (http://tinyurl.com/cat4a6g) were written before JDK7. With **IntelliJ** when you override a method the "Add Override" by default its checked. – GuilhE Jun 21 '15 at 14:46
  • This is such a promising lead. I have an activity which skims through a set of pages. But I notice when the page is not fully settled the page still of the previous page. I can notice this when I page through the view pager half way to the next page and logging in the output of the pages id. It turns out that the current page is always updated when the page is fully settled. Thus the current page is not current at all when transitioning between pages. – Neon Warge Sep 01 '15 at 13:45
  • Thanks a lot bro :) – Animesh Mangla Jul 31 '16 at 06:42
  • 2
    Note that `transformPage()` is called for multiple pages simultaneously, and some pages could end up having a different sign for its position value. –  Aug 11 '16 at 03:13
  • Thanks,but it only works well when the page is in the middle of the page list.I want to check swipe direction when it is the first page and the last page,how to check it ? – DawnYu Mar 16 '17 at 01:33
  • The approach of `PageTransformer` will return opposite result if the page is selected programmatically. – Sira Lam Dec 22 '17 at 03:57
21
  1. This is my simple solution in the onPageScrolled() method of ViewPager.OnPageChangeListener:

enter image description here

huu duy
  • 2,049
  • 21
  • 31
6

Same solution as GuilhE with a minor fix to avoid getting false positives when paging left (swiping right) on the first page(no more pages to the left) in the ViewPager. It simply does an additional check to see if the swipe has actually moved at all.

new ViewPager.OnPageChangeListener() {

  private static final float thresholdOffset = 0.5f;
  private static final int thresholdOffsetPixels = 1;
  private boolean scrollStarted, checkDirection;

  @Override
  public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    if (checkDirection) {
      if (thresholdOffset > positionOffset && positionOffsetPixels > thresholdOffsetPixels) {
        Log.i(C.TAG, "going left");
      } else {
        Log.i(C.TAG, "going right");
      }
    checkDirection = false;
  }
}

  @Override
  public void onPageSelected(int position) {}

  @Override
  public void onPageScrollStateChanged(int state) {
    if (!scrollStarted && state == ViewPager.SCROLL_STATE_DRAGGING) {
      scrollStarted = true;
      checkDirection = true;
    } else {
      scrollStarted = false;
    }
  }
 });
Kenneth Dixon
  • 104
  • 1
  • 5
3

You can keep class member variable to save last visited page

private int mLastVisitedPageIndex = 0;

Then use following function to check direction

@Override
public void onPageSelected(int i) {
    boolean isMovingForward = mLastVisitedPageIndex < i?true:false;
    //Use isMovingForward variable anywhere now
    mLastVisitedPageIndex = i;
}
Gagandeep Singh
  • 17,273
  • 1
  • 17
  • 18
3

use that

@Override
public void onPageSelected( int position )
{
    mCurrentFragmentPosition = position;
}
@Override
public void onPageScrolled( int position, float positionOffset, int positionOffsetPixels )
{
    boolean isGoingToRightPage = position == mCurrentFragmentPosition;
    if(isGoingToRightPage)
    {
        // user is going to the right page
    }
    else
    {
        // user is going to the left page
    }
}
ultra.deep
  • 1,699
  • 1
  • 19
  • 23
  • This is a very good solution, since it allows to monitor slide direction at any moment. Another solution http://stackoverflow.com/a/34356483/231590 monitors scroll direction during a single slide. – soshial Jul 26 '16 at 01:10
2

Use the ViewPager.OnPageChangeListener interface. You can use the position argument passed to onPageSelected and compare it to the previous value to figure out which way the ViewPager was scrolled.

Karakuri
  • 38,365
  • 12
  • 84
  • 104
2
private float sumPositionAndPositionOffset;

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    boolean isSwipeToLeft = position + positionOffset > sumPositionAndPositionOffset;
    sumPositionAndPositionOffset = position + positionOffset;   
}
Alexander Popov
  • 169
  • 1
  • 3
1

I solved the issue with this implementation. Hope it helps.

public static final float EPSILON= 0.001f;

@Override
public void onPageScrolled(final int position, final float positionOffset, final int positionOffsetPixels) {

    // initial position (positionOffset == 0)
    if (positionOffset < EPSILON) {
        mIsRight = positionOffset < 0.5;
        return;
    }

    // code here
    if (mIsRight) {
    } else {
    }
}
Muzaffer
  • 1,457
  • 1
  • 13
  • 22
1

We can also do this using a Custom Viewpager, which can contain swipeLeft() and swipeRight() methods and its onTouchEvent(MotionEvent event) method can contain ACTION_MOVE and ACTION_CANCEL case.

// This can be the code if helpful.

public class SwiperViewPager extends ViewPager {

    SwiperListener mSwiperListener;
    private float downX;
    private float downY;
    private boolean isTouchCaptured;
    private float upX1;
    private float upY1;
    private float upX2;
    private float upY2;

    public SwiperViewPager(Context context) {
        super(context);
    }

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

    private float x1, x2;
    static final int min_distance = 20;

    boolean eventSent = false;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE: {
                downX = event.getX();
                downY = event.getY();

                if (!isTouchCaptured) {
                    upX1 = event.getX();
                    upY1 = event.getY();
                    isTouchCaptured = true;
                } else {
                    upX2 = event.getX();
                    upY2 = event.getY();
                    float deltaX = upX1 - upX2;
                    float deltaY = upY1 - upY2;
                    //HORIZONTAL SCROLL
                    if (Math.abs(deltaX) > Math.abs(deltaY)) {
                        if (Math.abs(deltaX) > min_distance) {
                            // left or right
                            if (deltaX < 0) {
                                if(!eventSent && mSwiperListener!=null){
                                    mSwiperListener.onLeftSwipe();
                                    eventSent = true;
                                }
                            }
                            if (deltaX > 0) {
                                if(!eventSent && mSwiperListener!=null){
                                    if(mSwiperListener.onRightSwipe()){
                                        eventSent = true;
                                        return false;
                                    }
                                }
                            }
                        } else {
                            //not long enough swipe...
                        }
                    }
                    //VERTICAL SCROLL
                    else {
                        if (Math.abs(deltaY) > min_distance) {
                            // top or down
                            if (deltaY < 0) {

                            }
                            if (deltaY > 0) {

                            }
                        } else {
                            //not long enough swipe...
                        }
                    }
                }
            }
            break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:{
                isTouchCaptured = false;
                eventSent = false;
            }

        }
        return super.onTouchEvent(event);
    }

    public void setmSwiperListener(SwiperListener mSwiperListener) {
        this.mSwiperListener = mSwiperListener;
    }

    public static interface SwiperListener {
        public boolean onLeftSwipe();

        public boolean onRightSwipe();
    }

}
Jorgesys
  • 124,308
  • 23
  • 334
  • 268
JayJoshi
  • 81
  • 1
  • 1
  • 9
1

Apologies - had to edit the answer as I found a bug. Here is improved solution:

The solution compares current page index with one previously selected (previousPageIndex)

newPageIndex represents the page which is about to be scrolled to.

Condition (positionOffset == 0) compares if the scroll finished

private int previousPageIndex = 0;
private int newPageIndex = -1;

private final int MOVE_DIRECTION_NONE = 0;
private final int MOVE_DIRECTION_LEFT = 1;
private final int MOVE_DIRECTION_RIGHT = 2;

private int moveDirection = MOVE_DIRECTION_NONE;


@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    super.onPageScrolled(position, positionOffset, positionOffsetPixels);

    if (moveDirection == MOVE_DIRECTION_NONE) {
        if (previousPageIndex  == position){
            moveDirection = MOVE_DIRECTION_LEFT;
            if (newPageIndex == -1) newPageIndex = previousPageIndex + 1;
        }  else {
            moveDirection = MOVE_DIRECTION_RIGHT;
            if (newPageIndex == -1) newPageIndex = previousPageIndex - 1;
        }
    }

    if (positionOffset == 0) {
        System.out.println("Reseting");
        previousPageIndex = position;
        moveDirection = MOVE_DIRECTION_NONE;
        newPageIndex = -1;
    }

    switch (moveDirection) {
        case MOVE_DIRECTION_LEFT:
            if (onPageChangingHandler != null) onPageChangingHandler.pageChanging(previousPageIndex, newPageIndex, positionOffset);
            System.out.println("Sliding Left | Previous index: " + previousPageIndex + " | New Index: " + newPageIndex + " | offset: " + positionOffset  + " | Position: " + position);
            break;
        case MOVE_DIRECTION_RIGHT:
            if (onPageChangingHandler != null) onPageChangingHandler.pageChanging(newPageIndex, previousPageIndex, positionOffset);
            System.out.println("Sliding Right | Previous index: " + previousPageIndex + " | New Index: " + newPageIndex + " | offset: " + positionOffset + " | Position: " + position);
            break;
        case MOVE_DIRECTION_NONE:
            System.out.println("Moving NONE");
            break;
    }
}
  • Code-only answers are discouraged on Stack Overflow because they don't explain how it solves the problem. Please edit your answer to explain how it solves the question and how it improves on the long-time and upvoted answers this question has, so that it is useful to users with similar issues. – FluffyKitten Aug 20 '20 at 09:15
  • Apologies - added some short description – Ladislav Havlik Sep 01 '20 at 09:12
0
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        private int mCurrentSelectedScreen;
        private int mNextSelectedScreen;
        private static final float thresholdOffset = 0.5f;
        private boolean scrollStarted=true, checkDirection=false;
        ArrayList<Integer> comp_ary=new ArrayList<Integer>();

        @Override
        public void onPageSelected(int arg0) {
        }

        @Override
        public void onPageScrolled(int position, float positionOffset,
                int positionOffsetPixels) {

        //Log.e("positionOffsetPixels : "+positionOffsetPixels, "positionOffset : "+positionOffset);
        comp_ary.add(positionOffsetPixels);
             if (checkDirection) {
                    if (comp_ary.get(2) < comp_ary.get(comp_ary.size()-1)) {

                        Log.e("going left", "going left");
                    } else
                        if (comp_ary.get(2) > comp_ary.get(comp_ary.size()-1))
                    {

                        Log.e("going right", "going right");
                    }
                    checkDirection = false;
                    comp_ary=new ArrayList<Integer>();
                }
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {




            if (!scrollStarted && arg0 == ViewPager.SCROLL_STATE_SETTLING) {
                scrollStarted = true;
                checkDirection = true;
            } else {
                scrollStarted = false;
            }


        }
    });
0

dab on this if your worried about position offset suddenly changing to 0 after taking a value > 0.9F

    private boolean LEFT_DAB; //left swipe
    private float offset; //current position offset
    private float take_off; //previous position offset
    private static final float quavo = 0.5F; //position offset threshold

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        super.onPageScrolled(position, positionOffset, positionOffsetPixels);

        offset = take_off > 0.9F ? take_off : positionOffset;
        take_off = positionOffset;

        if (offset > quavo) {
            LEFT_DAB = false;//RIGHT_SWIPE
        } else {
            LEFT_DAB = true;//LEFT_SWIPE
        }
    }
linker
  • 821
  • 1
  • 8
  • 20
0

Here's a way you can know the scroll direction while it's happening. All you have to do is set an OnPageChangeCallback() on the ViewPager. You save the current page of the ViewPager in OnPageSelected() and compare it to the position parameter of OnPageScrolled(). If the current page is less than or equal to the position, you are scrolling to the right, if not, you are scrolling to the left.

var currentPage = 0
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        super.onPageSelected(position)
        currentPage = position
    }

    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {
        super.onPageScrolled(position, positionOffset, positionOffsetPixels)
        if (currentPage <= position) {
            // We are scrolling right
        } else {
            // We are scrolling left
        }
    }
})
Michael P
  • 225
  • 3
  • 11
-1
pager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            if(position  == pager.getCurrentItem()){
                // Move Right
            }
            else{
                // Move Left
            }

        }
KingWu
  • 370
  • 1
  • 4
  • 21