完美解决CoordinatorLayout AppBarLayout RecycleView 嵌套 AppBarLayout惯性下滑的问题

时间:2022-01-27 05:25:12
有人在YouTube上上传了现象  视频地址
* 上也有人讨论这个问题,视频也是在这个问题下面看到的。

这段时间在项目用到 AppBarLayout 加 RecyclerView的时候,fling 下滑的时候,AppBarLayout总是不跟随RecycleView下滑,导致让人看起来非常的不顺畅,这个应该是是bug,听说26sdk 已经解决了,但是我升级 了 编译sdk到26 确实解决了,但是结合Viewpage下去又出现了奇葩的滑动冲突,找了很久都没找到MOVE事件到底是被谁消费了。因此自己处理下这个问题。

解决方法:重写

AppBarLayout.Behavior
判断滚动方向,以及RecycleView 滚动停止,后重新计算Y方向速度,通知AppBarLayout进行Fling滚动即可。
 

import android.content.Context;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by xff on 2018/3/13.
 */

public final class FlingBehavior extends AppBarLayout.Behavior {

    private boolean isPositive;
    AppBarLayoutScrollListem appBarLayoutScrollListem ;
    public FlingBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        appBarLayoutScrollListem= new AppBarLayoutScrollListem(context);
    }


    @Override
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY) {
        if (target instanceof RecyclerView) {
            RecyclerView recyclerView = (RecyclerView) target;
            recyclerView.removeOnScrollListener(appBarLayoutScrollListem);
            recyclerView.addOnScrollListener(appBarLayoutScrollListem);
            appBarLayoutScrollListem.coordinatorLayout = coordinatorLayout;
            appBarLayoutScrollListem.child = child;
            appBarLayoutScrollListem.target = target;
            appBarLayoutScrollListem.velocityX = velocityX;
            appBarLayoutScrollListem.velocityY = velocityY;
            appBarLayoutScrollListem.consumed = false;
        }
        return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
    }

    @Override
    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) {
            appBarLayoutScrollListem.coordinatorLayout = coordinatorLayout;
            appBarLayoutScrollListem.child = child;
            appBarLayoutScrollListem.target = target;
            appBarLayoutScrollListem.velocityX = velocityX;
            appBarLayoutScrollListem.velocityY = velocityY;
            appBarLayoutScrollListem.consumed = consumed;
            appBarLayoutScrollListem.totalDy=0;
        }
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }


    public boolean onNestedFlingEx(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
        return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
    }

    @Override
    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;
    }

    public class AppBarLayoutScrollListem extends RecyclerView.OnScrollListener {
        AppBarLayout child;
        View target;
        CoordinatorLayout coordinatorLayout;
        float velocityX;
        float velocityY;
        boolean consumed;
        int totalDy=0;

        public AppBarLayoutScrollListem(Context context){
        }
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                if (child != null && target != null && coordinatorLayout != null) {
                    if (target instanceof RecyclerView) {
                        RecyclerView recyclerView1 = (RecyclerView) target;
                        final View firstChild = recyclerView.getChildAt(0);
                        final int childAdapterPosition = recyclerView.getChildAdapterPosition(firstChild);
                        if (childAdapterPosition == 0 && firstChild.getY() == 0) {
                            int velocityFinal= (int) (velocityY/(float)(child.getMeasuredHeight()+Math.abs(totalDy))*child.getMeasuredHeight());
                            onNestedFlingEx(coordinatorLayout, child, target, velocityX, velocityFinal, false);
                        }
                        recyclerView1.removeOnScrollListener(this);
                    }
                }
                clear();
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            totalDy+=dy;
        }

        public void clear() {
            totalDy=0;
            child = null;
            target = null;
            coordinatorLayout = null;
            velocityX = 0;
            velocityY = 0;
            consumed = false;
        }


    }

}