Den
Den

Reputation: 1352

Nested RecyclerView scrolling issue

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" />

Upvotes: 13

Views: 7738

Answers (5)

Rashid
Rashid

Reputation: 1

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>

Upvotes: 0

box
box

Reputation: 4688

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

Upvotes: 0

Rafiqul Hasan
Rafiqul Hasan

Reputation: 3622

<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

Upvotes: 0

Rajat Verma
Rajat Verma

Reputation: 5

 recyclerView.setNestedScrollingEnabled(false);

Upvotes: -3

Dhanumjay
Dhanumjay

Reputation: 525

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

Upvotes: -1

Related Questions