A-Android UCG
A-Android UCG

Reputation: 857

Horizontal RecyclerView inside ViewPager2 behavior

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

Answers (3)

Suhrab
Suhrab

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

Xi Wei
Xi Wei

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

Gomez NL
Gomez NL

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

Related Questions