tylerjroach tylerjroach - 4 months ago 211x
Android Question

Flinging with RecyclerView + AppBarLayout

I am using the new CoordinatorLayout with AppBarLayout and CollapsingToolbarLayout. Below AppBarLayout, I have a RecyclerView with a list of content.

I have verified that fling scrolling works on the RecyclerView when I am scrolling up and down the list. However, I would also like the AppBarLayout to smoothly scroll during expansion.

When scrolling up to expand the CollaspingToolbarLayout, scrolling immediately stops once lifting your finger off the screen. If you scroll up in a quick motion, sometimes the CollapsingToolbarLayout re-collapses as well. This behavior with the RecyclerView seems to function much differently than when using a NestedScrollView.

I've tried to set different scroll properties on the recyclerview but I haven't been able to figure this out.

Here is a video showing some of the scrolling issues.

Here is an example showing the issue with the RecyclerView (CheeseDetailActivity).

Here is the original example that uses a NestedScrollView from Chris Banes.


The answer of Kirill Boyarshinov was almost correct.

The main problem is that the RecyclerView sometimes is giving incorrect fling direction, so if you add the following code to his answer it works correctly:

public final class FlingBehavior extends AppBarLayout.Behavior {
    private static final int TOP_CHILD_FLING_THRESHOLD = 3;
    private boolean isPositive;

    public FlingBehavior() {

    public FlingBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);

    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
        if (velocityY > 0 && !isPositive || velocityY < 0 && isPositive) {
            velocityY = velocityY * -1;
        if (target instanceof RecyclerView && velocityY < 0) {
            final RecyclerView recyclerView = (RecyclerView) target;
            final View firstChild = recyclerView.getChildAt(0);
            final int childAdapterPosition = recyclerView.getChildAdapterPosition(firstChild);
            consumed = childAdapterPosition > TOP_CHILD_FLING_THRESHOLD;
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);

    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, int dx, int dy, int[] consumed) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
        isPositive = dy > 0;

I hope that this helps.