How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically?
You need to subclass ViewPager
. onTouchEvent
has a lot of good things in it that you don't want to change like allowing child views to get touches. onInterceptTouchEvent
is what you want to change. If you look at the code for ViewPager
, you'll see the comment:
/*
* This method JUST determines whether we want to intercept the motion.
* If we return true, onMotionEvent will be called and we do the actual
* scrolling there.
*/
Here's a complete solution:
First, add this class to your src
folder:
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller;
import java.lang.reflect.Field;
public class NonSwipeableViewPager extends ViewPager {
public NonSwipeableViewPager(Context context) {
super(context);
setMyScroller();
}
public NonSwipeableViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
setMyScroller();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// Never allow swiping to switch between pages
return false;
}
//down one is added for smooth scrolling
private void setMyScroller() {
try {
Class<?> viewpager = ViewPager.class;
Field scroller = viewpager.getDeclaredField("mScroller");
scroller.setAccessible(true);
scroller.set(this, new MyScroller(getContext()));
} catch (Exception e) {
e.printStackTrace();
}
}
public class MyScroller extends Scroller {
public MyScroller(Context context) {
super(context, new DecelerateInterpolator());
}
@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, 350 /*1 secs*/);
}
}
}
Next, make sure to use this class instead of the regular ViewPager
, which you probably specified as android.support.v4.view.ViewPager
. In your layout file, you'll want to specify it with something like:
<com.yourcompany.NonSwipeableViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
This particular example is in a LinearLayout
and is meant to take up the entire screen, which is why layout_weight
is 1 and layout_height
is 0dp.
And setMyScroller();
method is for smooth transition
The more general extension of ViewPager
would be to create a SetPagingEnabled
method so that we can enable and disable paging on the fly.
To enable / disable the swiping, just overide two methods: onTouchEvent
and onInterceptTouchEvent
. Both will return "false" if the paging was disabled.
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) {
return super.onTouchEvent(event);
}
return false;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
if (this.enabled) {
return super.onInterceptTouchEvent(event);
}
return false;
}
public void setPagingEnabled(boolean enabled) {
this.enabled = enabled;
}
}
Then select this instead of the built-in viewpager in XML
<mypackage.CustomViewPager
android:id="@+id/myViewPager"
android:layout_height="match_parent"
android:layout_width="match_parent" />
You just need to call the setPagingEnabled
method with false
and users won't be able to swipe to paginate.
The simplest way is to setOnTouchListener
and return true
for ViewPager
.
mPager.setOnTouchListener(new OnTouchListener()
{
@Override
public boolean onTouch(View v, MotionEvent event)
{
return true;
}
});