WonderCsabo
WonderCsabo

Reputation: 12207

ViewPager disable swiping to a certain direction

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?

Upvotes: 24

Views: 35291

Answers (7)

jwBurnside
jwBurnside

Reputation: 887

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.

Upvotes: 10

andre719mv
andre719mv

Reputation: 1498

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

Upvotes: 23

Ferran Ribell
Ferran Ribell

Reputation: 71

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

Upvotes: 3

Deepanshu
Deepanshu

Reputation: 209

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

Upvotes: 1

Aviv Mor
Aviv Mor

Reputation: 479

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.

Upvotes: 25

Ritesh Gune
Ritesh Gune

Reputation: 16739

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

Upvotes: 5

viplezer
viplezer

Reputation: 5599

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)

Upvotes: -3

Related Questions