Nested RecyclerView scrolling issue
Asked Answered
G

5

13

In my application I have vertical parent RecyclerView with few horizontal childs inside its ViewHolders. But I have pretty annoying scrolling issue - after I scroll parent RV vertically I want to scroll one of my child RVs but parent just intercepts all motion events until I remove my finger from screen and then put it back. Here's the example of this annoying behaviour.

https://i.imgur.com/dPtmAXD.gif

I tried every solution from this question - Nested RecyclerView. How to prevent parent RecyclerView from getting scrolled while child RecyclerView is scrolling?

Nothing works for me.

It looks like Google Play Market has the same RV hierarchy, but ofc scroll is perfectly fine. I tried to implement few solutions from other topics, but nothing works as intended.

I don't know what code should I post, but here's my Parent RV's ViewHolder example with nested RV.

private class UserEventsViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        private RecyclerView rvUserEvents;
        private HomeUserEventsRVAdapter rvAdapter;

        public UserEventsViewHolder(View v) {
            super(v);

            rvUserEvents = v.findViewById(R.id.rv_user_events);
            rvUserEvents.setLayoutManager(new LinearLayoutManager(itemView.getContext(), LinearLayoutManager.HORIZONTAL, false));
            rvUserEvents.setNestedScrollingEnabled(false);
            rvUserEvents.setRecycledViewPool(viewPool);
            rvAdapter = new HomeUserEventsRVAdapter(presenter);
            rvUserEvents.setAdapter(rvAdapter);

            v.findViewById(R.id.btn_all_user_events).setOnClickListener(this);
        }

        private void bind(UserItemViewModel userItem) {
            rvAdapter.updateAdapter(userItem);
        }

        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.btn_all_user_events:
                    presenter.openUserEventsList();
                    break;
            }
        }
    }

EDIT: XML code for my activity

<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cl_root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">

<android.support.design.widget.AppBarLayout
    android:id="@+id/ab_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="190dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        android:fitsSystemWindows="true"
        app:contentScrim="@android:color/white"
        app:expandedTitleMarginStart="48dp"
        app:expandedTitleMarginEnd="64dp">

        <ImageView
            android:id="@+id/iv_pic"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/ic_home_screen_background"
            android:fitsSystemWindows="true"
            app:layout_collapseMode="parallax"
            app:layout_collapseParallaxMultiplier="0.5"/>

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:elevation="7dp"
            android:theme="@style/ToolbarTheme"
            app:layout_collapseMode="pin"/>
    </android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>

<android.support.v4.widget.SwipeRefreshLayout
    android:id="@+id/sr_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="-6dp"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rv_results"
        android:clipToPadding="false"
        android:scrollbars="vertical"
        android:scrollbarThumbVertical="@color/orange_juice_80"
        android:scrollbarSize="2dp"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/shape_rounded_top_grey"
        android:fitsSystemWindows="true" />
</android.support.v4.widget.SwipeRefreshLayout>

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab_add"
    android:layout_width="56dp"
    android:layout_height="56dp"
    android:layout_marginEnd="15dp"
    app:backgroundTint="@color/dark_background"
    app:layout_anchor="@id/rv_results"
    app:layout_anchorGravity="top|right|end"
    app:layout_scrollFlags="scroll|exitUntilCollapsed"
    app:srcCompat="@drawable/ic_vector_plus_white" />

Gehman answered 4/4, 2018 at 13:14 Comment(8)
Your link to the GIF has expired. My Play Store exhibits the behavior that you are seeing in your app. Where, specifically, do you see the alternate behavior in the Play Store app?Dyslogia
In the Play Store app you can scroll the parent RV fast, then just put your finger on one of the childs while parent's still scrolling - this action stops parent vertical scrollin and now you can scroll child straight away. As i said, In my application if I scroll parent vertical RV fast I have to put my finger on screen once just to stop parent scrolling, then I have to get my finger off the screen and put it back to scroll child. If I'm tryng to child with my first touch, parent intercepts swipes. @DyslogiaGehman
Updated gif link @DyslogiaGehman
Any progress? Any solution? I have same problem.Gnathic
From what I understand you need to play around with MotionEvents passing down between RecyclerViews. I could probably work on a solution if you can provide a Minimum Verifiable Example.Nicol
Please add HomeUserEventsRVAdapter's view holderSacrifice
Have you all looked at - #34549914 - github.com/Ranjan101/RecyclerView-Google-Play - khmertechtrain.tk/index.php/2017/10/03/…Avila
Try to put child items RecyclerView in a RelativeLayout or LinearLayoutRiggall
A
0
<androidx.recyclerview.widget.RecyclerView
     android:id="@+id/recyclerView"
     android:layout_width="match_parent"
     android:descendantFocusability="blocksDescendants"
     android:layout_height="wrap_content"
     android:scrollbars="none" />

Use android:descendantFocusability="blocksDescendants" attribute inside nested recyclerview

Apiary answered 18/6, 2019 at 9:56 Comment(0)
T
0

The problem with nested RecyclerView is that the correct slope of the finger fling is not detected correctly.

Here is a snippet of code that actually calculates the correct slope of the fling https://github.com/minarja1/NestedRecyclerSample/blob/developv2/app/src/main/java/com/example/nestedrecyclersample/utils/ViewExtensions.kt

After you add the class to your codebase, you can call the function with a Kotlin Extension.

fun RecyclerView.enforceSingleScrollDirection() {
    val enforcer = SingleScrollDirectionEnforcer()
    addOnItemTouchListener(enforcer)
    addOnScrollListener(enforcer)
}
Throb answered 25/8, 2021 at 12:5 Comment(0)
V
0

Bit late but want to share so that if someone suffer from this in future.

If you're using XML specifically ConstraintLayout for your UI -> then use RelativeLayout for specific recyclerview child. write recyclerview (androidx.recyclerview.widget.RecyclerView) inside RelativeLayout. it scrolls smothly with RelativeLayout.

you'll not require any extra tag or attribute For instance:

   <androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_width="match_parent">

<androidx.core.widget.NestedScrollView
    android:fillViewport="true"
    android:id="@+id/nestedView"
    android:layout_height="match_parent"
    android:layout_marginTop="40dp"
    android:layout_width="match_parent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_height="match_parent"
        android:layout_width="match_parent"

    .
    .
    .

    <RelativeLayout
        android:id="@+id/rvPasser1"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        app:layout_constraintTop_toBottomOf="@+id/llPassingFromMenuA">

        <androidx.recyclerview.widget.RecyclerView
            android:background="@drawable/list_box"
            android:id="@+id/rv"
            android:layout_height="wrap_content"
            android:layout_width="match_parent" />
    </RelativeLayout>
    .
    .
    .
   </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

</androidx.constraintlayout.widget.ConstraintLayout>

Vulturine answered 19/4, 2024 at 11:2 Comment(0)
T
-1

You disabled the nested scrolling of RecyclerView in this line

rvUserEvents.setNestedScrollingEnabled(false);

You need to replace this line with below to scrolling work properly

ViewCompat.setNestedScrollingEnabled(rvUserEvents,true);
Tomas answered 4/4, 2018 at 13:23 Comment(2)
Well, I did this because I'm using collapsingToolbarLayout with my parent RV. If I remove this line collapsingToolbarLayout will never collapse again.Gehman
I tried your solution - doesn't work, same behaviour.Gehman
M
-3
 recyclerView.setNestedScrollingEnabled(false);
Margay answered 1/1, 2020 at 7:54 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.