Reputation: 857
I have a ViewPager2 with fragments inside it.
One of the fragments has 2 RecyclerViews, both of which are Horizontal Linear.
When you touch on the RecyclerView, the ViewPager handles the swipe gestures instead, and doesn't scroll the RecyclerView.
The RecyclerViews and the ViewPager both are inside NestedScrollView, but that doesn't change anything.
The only way to scroll the RecyclerView is doing a slow swipe gesture on the RecyclerView, that way, the RecyclerView handles the swipe gesture instead of the ViewPager, but of course, that is not convenient for a user.
How can I make the RecyclerView handle the scrolling when it's touched, and disable the ViewPager's handling when the touch is inside the RecyclerView.
P.S : I know most will say that is not recommended, Google Play Store has the same view but the ViewPager isn't scrollable, instead, the user is supposed to use the TabLayout to navigate the pages.
Upvotes: 3
Views: 1922
Reputation: 31
I searched for a very long time on all possible sites for solutions to this question but I had to experiment and make my own code please.
Try below for kotlin
recyclerView.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean {
when (e.action) {
MotionEvent.ACTION_MOVE -> viewPager2!!.isUserInputEnabled = false
else -> viewPager2!!.isUserInputEnabled = true
}
return false
}
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) {
TODO("Not yet implemented")
}
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {
TODO("Not yet implemented")
}
Upvotes: 1
Reputation: 1679
fun ViewPager2.reduceDragSensitivity() {
val recyclerViewField = ViewPager2::class.java.getDeclaredField("mRecyclerView")
recyclerViewField.isAccessible = true
val recyclerView = recyclerViewField.get(this) as RecyclerView
val touchSlopField = RecyclerView::class.java.getDeclaredField("mTouchSlop")
touchSlopField.isAccessible = true
val touchSlop = touchSlopField.get(recyclerView) as Int
touchSlopField.set(recyclerView, touchSlop*8) // "8" was obtained experimentally
}
The above code will reduce the sensitivity of the ViewPager2
. Here is the source of the article: https://al-e-shevelev.medium.com/how-to-reduce-scroll-sensitivity-of-viewpager2-widget-87797ad02414
Upvotes: 2
Reputation: 942
This is what I've defined for my case and can be applied dynamically to any recycler view in the ViewPager2
public void controlHorizontalScrollingInViewPager2(RecyclerView recyclerView, ViewPager2 viewPager2) {
RecyclerView.OnItemTouchListener onTouchListener = new RecyclerView.OnItemTouchListener() {
int lastX = 0;
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) e.getX();
break;
case MotionEvent.ACTION_MOVE:
boolean isScrollingRight = e.getX() < lastX;
if ((isScrollingRight && ((LinearLayoutManager) recyclerView.getLayoutManager()).findLastCompletelyVisibleItemPosition() == recyclerView.getAdapter().getItemCount() - 1) ||(!isScrollingRight && ((LinearLayoutManager) recyclerView.getLayoutManager()).findFirstCompletelyVisibleItemPosition() == 0)) {
viewPager2.setUserInputEnabled(true);
} else {
viewPager2.setUserInputEnabled(false);
}
break;
case MotionEvent.ACTION_UP:
lastX = 0;
viewPager2.setUserInputEnabled(true);
break;
}
return false;
}
@Override
public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
};
recyclerView.addOnItemTouchListener(onTouchListener);
}
Usage:
controlHorizontalScrollingInViewPager2(yourRecyclerView,mViewPager2);
Check out the similar issue reported here ViewPager2 with horizontal scrollView inside
Upvotes: 1