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:
- 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*/);
}
}
}
- 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>
- 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
Imageview of Png Doesn't Appear (Maybe It's Too Big)
How to Control Navigationview Margin Between Menu Items
How to Scroll Scrollview to Bottom Programmatically in Android
Prevent Screen Rotation on Android
How to Get Context in Android Mvvm Viewmodel
How to Open Draw Overlay Permission Popup in Miui
How to Keep a Bottom Nav Bar from Being Pushed Up on Keyboard Shown
Adb.Exe Not Found After Installing Android Studio
How to Use Python to Execute Adb Commands
How to Check If a Value Exists Already in a Firebase Data Class Android
How to Go Back to Previous Fragment from Activity
Why Livedata Observer Is Being Triggered Twice for a Newly Attached Observer
How to Check If the Current Activity Has a Dialog in Front
Waiting Till the Async Task Finish Its Work
How to Clear Livedata Stored Value
How to Close/Hide the Android Soft Keyboard Programmatically
How to Make a Background 20% Transparent on Android
Android Sqlite: How to Retrieve Specific Data from Particular Column