24

I want to disable the swiping, but only to the right side. I found a working solution in this answer. Unfortunately, this copies the whole ViewPager source to achieve the goal. Is there any methods just inheriting the existing class and not duplicating?

Community
  • 1
  • 1
WonderCsabo
  • 11,947
  • 13
  • 63
  • 105
  • Are you bound to use vanilla ViewPager? – Shark Sep 06 '13 at 14:24
  • If there is a lib which contains a `ViewPager` with this behavior, i can use it BTW. Note that i want to dynamically enable and disable right swiping, not just disable it statically. – WonderCsabo Sep 06 '13 at 14:27
  • I suppose you could try overriding onTouchEvent or onInterceptTouchEvent and try to filter out the touch events you don't want it to respond to (and call super for the rest). – Karakuri Sep 06 '13 at 14:27
  • Actually i have to copy everything because i want to modify a private method. :( – WonderCsabo Sep 06 '13 at 14:29
  • Preventing swipes is really easy, a single method call. Preventing them only to one side could prove a bit more difficult... – Shark Sep 06 '13 at 14:31
  • Create an object that extend ViewPager and do the custom work ;) – An-droid Sep 06 '13 at 14:31

7 Answers7

25

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.

Aviv Mor
  • 469
  • 6
  • 6
  • 2
    Thanks! This is an old question, i already resolved this (via dropping `ViewPager` and using `Fragment` animations so i can completely control the flow). I think yours is a good solution, so i am accepting it. :) – WonderCsabo Feb 06 '14 at 13:46
  • 1
    how did you do this can you share a snippet? how did you disable the swap on right side with this example. – badarshahzad Apr 17 '18 at 10:07
23

Here is working ViewPager class with possibility to disable any direction paging. Check out all the answer here .

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;
    }
Community
  • 1
  • 1
andre719mv
  • 1,478
  • 13
  • 14
10

Another simple way is to use setCurrentItem() to scroll back to the desired slide if you hit a certain position. For instance, this will only allow forward swiping:

mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}

    @Override
    public void onPageSelected(int position) {
        if(position < mProgress) {
            mViewPager.setCurrentItem(mProgress, true);
        } else {
            mProgress = position;
        }
    }

    @Override
    public void onPageScrollStateChanged(int state) {}
});

Or if you want to have a max slide:

if(position > 4) {
    mViewPager.setCurrentItem(4, true);
}

This solution will technically not completely disable the swipe, as you'll still see a small portion of the disallowed slide when you make your swipe movement. But for some applications this may be preferred.

jwBurnside
  • 849
  • 4
  • 31
  • 66
4

You can try following:

Step 1: Create a new custom class say "CustomViewPager". The class inherits from "ViewPager" and includes a new customised method called "setPagingEnabled" with a purpose to enable / disable the swiping, depending on the requirement.

Step2 : Override two methods: "onTouchEvent" and "onInterceptTouchEvent". Both will return "false" if the paging is to be disabled completely.

Step 3: Substitute the "ViewPager" tag on the layout file with customized class:

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

Step 4: CustomViewPager.java

    public class CustomViewPager extends ViewPager {

private boolean enabled;

public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.enabled = true;
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (this.enabled && detectSwipeToRight(event)) {
        return super.onTouchEvent(event);
    }

    return false;
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (this.enabled && detectSwipeToRight(event)) {
        return super.onInterceptTouchEvent(event);
    }

    return false;
}

// To enable/disable swipe 
public void setPagingEnabled(boolean enabled) {
    this.enabled = enabled;
}

// Detects the direction of swipe. Right or left. 
// Returns true if swipe is in right direction
public boolean detectSwipeToRight(MotionEvent event){

 int initialXValue = 0; // as we have to detect swipe to right
 final int SWIPE_THRESHOLD = 100; // detect swipe
 boolean result = false;

        try {                
            float diffX = event.getX() - initialXValue;

                if (Math.abs(diffX) > SWIPE_THRESHOLD ) {
                    if (diffX > 0) {
                        // swipe from left to right detected ie.SwipeRight
                        result = false;
                    } else {
                        // swipe from right to left detected ie.SwipeLeft
                        result = true;
                    }
                }
            } 
         catch (Exception exception) {
            exception.printStackTrace();
        }
        return result;
    }
}
Ritesh Gune
  • 16,629
  • 6
  • 44
  • 72
  • 5
    I tried the updated answer. `diffX` is always positive, so the method never returns `true`. – WonderCsabo Sep 06 '13 at 15:48
  • Hi wonderCsabo : did you get any soluton for the same ? i also tried lots of but still this type issue facing. Waiting for your replay. Thanks in advance. – Teraiya Mayur May 07 '15 at 06:18
  • This doesn't detect a swipe, it just detects if the first (and every subsequent) motion event X coordinate is greater than 0. This should always return false because X will always be positive. – Hamid May 15 '15 at 14:41
  • yes Hamid ,due to to this it disables swipe in both directions. – Mansuu.... Aug 08 '16 at 08:55
3

You can use the methods beginFakeDrag() and endFakeDrag().

beginFakeDrag() when you want disable the swipe and endFakeDrag() if you want enable again.

Like this: viewPager.beginFakeDrag();

Sven Rojek
  • 5,476
  • 2
  • 35
  • 57
1
private float initialXValue;
@Override
public boolean onTouchEvent(MotionEvent event) {
    if (this.mEnabled) {
        return super.onTouchEvent(event);
    }
    if(event.getAction()==MotionEvent.ACTION_DOWN){
        initialXValue = event.getX();
    }else if(event.getAction()==MotionEvent.ACTION_MOVE){
        if(detectSwipeToRight(event)){
            System.out.println("right swipe detected");
        }
    }
    return true;
}

private boolean detectSwipeToRight(MotionEvent event) {
    final int SWIPE_THRESHOLD = 100; // detect swipe
    boolean result = false;

    try {
        float diffX = event.getX() - initialXValue;
        if (Math.abs(diffX) > SWIPE_THRESHOLD) {
            if (diffX < 0) {
                // swipe from right to left detected ie.SwipeLeft
                result = true;
            }
        }
    } catch (Exception exception) {
        exception.printStackTrace();
    }
    return result;
}
Deepanshu
  • 209
  • 1
  • 2
  • 8
-3

You have to create your own ViewPager subclass and override the canScrollHorizontally function

http://developer.android.com/reference/android/support/v4/view/ViewPager.html#canScrollHorizontally(int)

viplezer
  • 5,519
  • 1
  • 18
  • 25