How to disable ViewPager from swiping in one direction

I want to allow the user swipe in a ViewPager only from right to left. So once he passed a page he can’t come back to it. How can this be done?

I tried this solution:

  • Why do so many Android apps use the NDK?
  • Using the “animated circle” in an ImageView while loading stuff
  • MarkerClick works but InfoWindowClick does not open ViewModel
  • Android Studio Update Project: Merge vs Rebase vs Branch Default
  • Android device information
  • Android rotate TextView in API Level >= 8
  • public class CustomViewPager extends ViewPager {
    
    float lastX = 0;
    
    boolean lockScroll = false;
    
    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public CustomViewPager(Context context) {
        super(context);
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
    
        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lastX = ev.getX();
            lockScroll = false;
            return super.onTouchEvent(ev);
        case MotionEvent.ACTION_MOVE:
    
            if (lastX > ev.getX()) {
                lockScroll = false;
            } else {
                lockScroll = true;
            }
    
            lastX = ev.getX();
            break;
        }
    
        lastX = ev.getX();
    
        if(lockScroll) {
            return false;
        } else {
            return super.onTouchEvent(ev);
        }
    }
    }
    

    But it still allows me to poorly swipe in the other direction.

  • Android Webview app won't let video player go full screen
  • display data after every 10 seconds in Android
  • Cursor is not visible in EditText when no text is there
  • When to unsubscribe a subscription
  • What is the relationship between Looper, Handler and MessageQueue in Android?
  • Android LinearLayout with color resource: What am I doing wrong?
  • 4 Solutions collect form web for “How to disable ViewPager from swiping in one direction”

    There is one more event you miss: onInterceptTouchEvent. It`s must contain the same logic as onTouchEvent.

    My complete solution is based on this answer. It will allow you to enable/disable paging in any direction in any time you need.

    1. Create enum

     public enum SwipeDirection {
        all, left, right, none ;
    }
    

    2.Extend ViewPager

    public class CustomViewPager extends ViewPager {
    
        private float initialXValue;
        private SwipeDirection direction;
    
        public CustomViewPager(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.direction = SwipeDirection.all;
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            if (this.IsSwipeAllowed(event)) {
                return super.onTouchEvent(event);
            }
    
            return false;
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent event) {
            if (this.IsSwipeAllowed(event)) {
                return super.onInterceptTouchEvent(event);
            }
    
            return false;
        }
    
        private boolean IsSwipeAllowed(MotionEvent event) {
            if(this.direction == SwipeDirection.all) return true;
    
            if(direction == SwipeDirection.none )//disable any swipe
                return false;
    
            if(event.getAction()==MotionEvent.ACTION_DOWN) {
                initialXValue = event.getX();
                return true;
            }
    
            if(event.getAction()==MotionEvent.ACTION_MOVE) {
                try {
                    float diffX = event.getX() - initialXValue;
                    if (diffX > 0 && direction == SwipeDirection.right ) {
                        // swipe from left to right detected
                        return false;
                    }else if (diffX < 0 && direction == SwipeDirection.left ) {
                        // swipe from right to left detected
                        return false;
                    }
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
    
            return true;
        }
    
        public void setAllowedSwipeDirection(SwipeDirection direction) {
            this.direction = direction;
        }
    

    3.Use your viewPager in a layout

     <package_name.customviewpager 
         android:id="@+id/customViewPager" 
         android:layout_height="match_parent" 
         android:layout_width="match_parent" />
    

    4.Enable any swipe direction in code. Default is all (right and left)

    mViewPager.setAllowedSwipeDirection(SwipeDirection.right);
    

    Define your adapter like this

    public class MyFragmentStatePagerAdapter extends FragmentStatePagerAdapter {
    
        private final int totalPages = 10;
        private int currentPage = 0;
    
        public MyFragmentStatePagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public Fragment getItem(int position) {
            // Use whatever logic you want here to
            // to select a fragment based on
            // currentPage instead of position
    
            if (currentPage % 2 == 0) {
                return new Fragment1();
            } else {
                return new Fragment2();
            }
        }
    
        @Override
        public int getCount() {
            return currentPage == totalPages ? 1 : 2;
        }
    
        @Override
        public int getItemPosition(Object object){
            return PagerAdapter.POSITION_NONE;
        }
    
        public void nextPage() {
            currentPage++;
            notifyDataSetChanged();
        }
    }
    

    In the fragment that is using the view pager, do this

    @Override
    public void onPageSelected(int arg0) {
        if (arg0 > 0) {
            pagerAdapter.nextPage();
            pager.setCurrentItem(0, false);
        }
    }
    

    Try to add (the same logic like in onTouchEvent )

    @Override
    public boolean onInterceptTouchEvent(MotionEvent arg0) {
        // allow/ not allow swiping to switch between pages
        return !lockScroll ;
    }
    
    package com.contacts_app.jamison.contacts__proprivacy4;
    
    import android.content.Context;
    import android.content.res.Resources;
    import android.support.v4.view.ViewPager;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    
    public class ViewPager_Settings extends ViewPager
    {
    private final String TAG = ViewPager_Settings.class.getSimpleName();
    public float startX;
    
    public ViewPager_Settings(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
     ////////////////////////////////////////////////////////////////////////////////////////////////
    public static int dpTOpx(double dp)
    {
        return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
    }
    public static int pxTOdp(double px)
    {
        return (int) (px / Resources.getSystem().getDisplayMetrics().density);
    }
    ////////////////////////////////////////////////////////////////////////////////////////////////
    
    /*****DispatchTouchEvent for the View Pager to intercept and block swipes Right*****/
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev)
    {
        final int actionMasked = ev.getActionMasked() & MotionEvent.ACTION_MASK;
        //int movement_limit = pxTOdp(50);
        switch (actionMasked)
        {
            case (MotionEvent.ACTION_DOWN):
            {
                startX = ev.getX();
                Log.i(TAG, "startX: " + startX);
    
                /*Should always be this below*/
                return super.dispatchTouchEvent(ev);
            }
            case (MotionEvent.ACTION_MOVE):
            {
                Log.i(TAG, "ev.getX() - startX:" + (ev.getX() - startX));
    
                /*Switching directional changes would be a matter of flipping the  "<" sign in the line below.*/
                if (ev.getX() - startX > 0)
                {
                    /*The result is that the ViewPager will not swipe from left*/
                    ev.setAction(MotionEvent.ACTION_CANCEL);;
                }
    
                /*Should always be this below*/
                super.dispatchTouchEvent(ev);
            }
            /**The ACTION_UP case statement is only needed if you don't want to pass down the touch event 
            * to buttons that may receive the click after the swipe is blocked.*/
            /*case (MotionEvent.ACTION_UP):
            {
                //Log.i(TAG, "movement_limit: " + movement_limit);
    
                //(-50) may need to be changed to something more broader in scope to accompany all screen densities
                if ( (ev.getX() - startX) < (-50) )
                {
                    ev.setAction(MotionEvent.ACTION_CANCEL);
                }
    
                //Should always be this below
                super.dispatchTouchEvent(ev);
            }*/
        }
        /*Should always be this below*/
        return super.dispatchTouchEvent(ev);
    }
     ////////////////////////////////////////////////////////////////////////////////////////////////
    
    }/*****END OF FILE*****/
    

    Don’t forget to change the line at the top to put the package name of your App.
    Also most, if not all, of the comments give insight into what the code is doing in case you decide you want to tinker with things.

    Android Babe is a Google Android Fan, All about Android Phones, Android Wear, Android Dev and Android Games Apps and so on.