How to Disable Viewpager from Swiping in One Direction

ViewPager disable swiping to a certain direction

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.

How to disable swiping in specific direction in ViewPager2

I found a listener which can listen when the user tries to swipe, it'll then check the current page, if it's the first page, disable the user input else enable it as it was by default.

Here's the code snippet for that

In Java:

pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);

if (state == SCROLL_STATE_DRAGGING && pager.getCurrentItem() == 0) {
pager.setUserInputEnabled(false);
} else {
pager.setUserInputEnabled(true);
}
}
});

In Kotlin:

viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback() {
override fun onPageScrollStateChanged(state: Int) {
super.onPageScrollStateChanged(state)

viewPager.isUserInputEnabled = !(state == SCROLL_STATE_DRAGGING && viewPager.currentItem == 0)
}
})

Since my scenario was of 2 pages only, checking the page number would be good for me, but in case we have more than 2 pages and we need to disable the swipe in one particular direction, we may use onPageScrolled(int position, float positionOffset, int positionOffsetPixels) listener of viewpager2 and handle the desired scenario according to the positive or negative values of position and positionOffset.

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

How do I disable the swipe function in this particular viewpager?

You need to create a custom ViewPager that intercepts the onTouch events and avoid the default behaviour. This way the user wont be able to swipe between pages but will be able to touch on the tabs.

You can check this link where is already answered: How do disable paging by swiping with finger in ViewPager but still be able to swipe programmatically?

EDIT

I'll explain it by steps:

  1. Create a new class called NonSwipeableViewPager
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*/);
}
}
}

  1. Modify your layout to use the new ViewPager
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">


<android.support.design.widget.TabLayout
android:id="@+id/tabs"
app:tabGravity="fill"
app:tabMode="fixed"
android:background="@color/material_blue_grey_800"
app:tabIndicatorColor="@color/orange"
app:tabSelectedTextColor="@color/orange"
app:tabTextColor="@color/white"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</android.support.design.widget.TabLayout>

<NonSwipeableViewPager <!-- You will need to import this correctly with your class package -->
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="50dp">

</NonSwipeableViewPager>



</LinearLayout>

  1. Update your activity with the new ViewPager
public class TabFragment extends Fragment {
public static TabLayout tabLayout;
public static NonSwipeableViewPager viewPager; // This line changed
public static int int_items = 2 ;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {


View x = inflater.inflate(R.layout.tab_layout,null);
tabLayout = (TabLayout) x.findViewById(R.id.tabs);
viewPager = (NonSwipeableViewPager) x.findViewById(R.id.viewpager); // This line changed

viewPager.setAdapter(new MyAdapter(getChildFragmentManager()));

viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}



tabLayout.post(new Runnable() {
@Override
public void run() {
tabLayout.setupWithViewPager(viewPager);
}
});

return x;

}

You can keep the same adapter MyAdapter.

This will avoid the swipe between tabs but will keep the click on each one.

How to disable swiping in ViewPager2?

Now it is possible to enable-disable swiping viewpager2 using Version 1.0.0-alpha02

Use implementation 'androidx.viewpager2:viewpager2:1.0.0-alpha02'

Version 1.0.0

New features

  • Ability to disable user input (setUserInputEnabled, isUserInputEnabled)

API changes

  • ViewPager2 class final

Bug fixes

  • FragmentStateAdapter stability fixes

SAMPLE CODE to disable swiping in viewpager2

myViewPager2.setUserInputEnabled(false);

SAMPLE CODE to enable swiping in viewpager2

myViewPager2.setUserInputEnabled(true);

Viewpage stop swiping in a certain direction

You will have to make your own ViewPager that extends the original ViewPager and override the onTouchEvent method

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

}



}


Related Topics



Leave a reply



Submit