Search code examples
androidandroid-recyclerviewandroid-coordinatorlayout

onNestedScroll not giving dy when vertical scrolling was initiated by touching a horizontal scrolling child and then scrolling vertically


I have a coordinator layout that contains a vertical recycler view of horizontal recycler views.

I have defined a CoordinatorLayout.Behavior that uses onNestedScroll to do some things to my views based on the dyConsumed.

It works if you scroll by touching anywhere outside of the horiztonal recycler views, and then scrolling vertically.

It sometimes works if you fling at the end of your scroll.

It does not work if you touch a horizontal recycler view and then scroll vertically.

It just generally has very inconsistent behavior. Like, sometimes it won't care where you started your scroll, until one of the horizontal recyclers has been scrolled, then it'll stop working again.

I tried changing the Behavior to give me as much I could get it to give me by having onStartNestedScroll always return true and moving my handling code to onNestedPreScroll. By doing so, I now get dy updates for the vertical movement of their finger when scrolling horizontally in the child recycler. But I still do not get any dy for scrolling vertically if the touch started on a horizontal recycler.

What do I have to do to get all vertical scrolling dy no matter where the touch was initiated?

Setting the behavior for the constraint layout that contains everything (and is contained by a Coordinator Layout)

CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) ((ConstraintLayout) toolbar.getParent()).getLayoutParams();
layoutParams.setBehavior(scrollBehavior);

Excerpt from custom Behavior

@Override
public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull V child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) {
    return axes == ViewCompat.SCROLL_AXIS_VERTICAL;
}
@Override
public void onNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
                           @NonNull V child,
                           @NonNull View target,
                           int dxConsumed,
                           int dyConsumed,
                           int dxUnconsumed,
                           int dyUnconsumed,
                           int type) {

    if (dyConsumed > 0) {
        //stuff
    } else if (dyConsumed < 0) {
        //other stuff
    }
}

My vertical recycler

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/bucket_list"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:clipToPadding="false"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

My horizontal recycler

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/store_list"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:paddingEnd="32dp"
    android:paddingRight="32dp"
    android:clipToPadding="false"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

Solution

  • Counter-intuitively, the solution was to disable nested scrolling on the horizontal recyclers with android:nestedScrollingEnabled="false"