支持 NestedScrollView 与 RecyclerView 嵌套双滑动的布局管理器

NestedScrollView 与 RecyclerView 的嵌套使用问题,在网上看到的都是说给 RecyclerView 设置 setNestedScrollingEnabled(false)。但是这个方法会有一个问题,
那就是要求 RecyclerView 的高度是 wrap_content 的 (要不然高度太小了,底部的 Item View 滑动不出来),即有多少 Item View,就得要有相应的多大高度。但这不是我想要的,一是这会导致 ViewHolder 不能被回收!!!RecyclerView 就失去了 Recycle 的意义!!! 二是在向顶部快速 fling 滑动的时候,整体滑动效果不连贯。 有人还称这个方法很优雅,其实一点也不优雅。。。

上视频看看使用前,使用后分别是什么样的效果:

before

after

(原创作品,转载请声明出处:https://blog.csdn.net/hegan2010/article/details/113103751)

为了解决这个问题,使得 NestedScrollView 与 RecyclerView 可以双滑动,并且不产生滑动冲突,写了一个布局管理器。
原理是,在RecyclerView的可见区域顶部低于 NestedScrollView 可见区域顶部时,减少 RecyclerView 在Y轴上消费掉滑动距离,或者设为0,或者为两者高度距离差,让NestedScrollView 消费掉更多的滑动距离。

实现代码如下(继承自GridLayoutManager,可以根据实际情况修改为继承自哪个LayoutManager,只要重载了 scrollVerticallyBy 方法就行):

import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import androidx.core.view.ScrollingView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import java.lang.reflect.Field;

public class AutoScrollGridLayoutManager extends GridLayoutManager {
    
    
    public AutoScrollGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr,
            int defStyleRes) {
    
    
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public AutoScrollGridLayoutManager(Context context, int spanCount) {
    
    
        super(context, spanCount);
    }

    public AutoScrollGridLayoutManager(Context context, int spanCount, int orientation,
            boolean reverseLayout) {
    
    
        super(context, spanCount, orientation, reverseLayout);
    }

    @Override
    public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
            RecyclerView.State state) {
    
    
        if (dy <= 0) {
    
    
            return super.scrollVerticallyBy(dy, recycler, state);
        }
        RecyclerView recyclerView = getRecyclerView();
        if (recyclerView == null) {
    
    
            return super.scrollVerticallyBy(dy, recycler, state);
        }
        ViewGroup parentView = getParentScrollingView(recyclerView);
        if (parentView == null) {
    
    
            return super.scrollVerticallyBy(dy, recycler, state);
        }
        Rect parentVisibleRect = new Rect();
        parentView.getGlobalVisibleRect(parentVisibleRect);
        Rect recyclerVisibleRect = new Rect();
        recyclerView.getGlobalVisibleRect(recyclerVisibleRect);
        int verticalOffset = recyclerVisibleRect.top - parentVisibleRect.top;
        if (verticalOffset <= 0) {
    
    
            return super.scrollVerticallyBy(dy, recycler, state);
        } else {
    
     // verticalOffset > 0
            if (dy <= verticalOffset) {
    
    
                return 0;
            } else {
    
     // dy > verticalOffset
                return super.scrollVerticallyBy(dy - verticalOffset, recycler, state);
            }
        }
    }

    public RecyclerView getRecyclerView() {
    
    
        try {
    
    
            Field field = RecyclerView.LayoutManager.class.getDeclaredField("mRecyclerView");
            field.setAccessible(true);
            return (RecyclerView) field.get(this);
        } catch (ReflectiveOperationException e) {
    
    
            return null;
        }
    }

    public static ViewGroup getParentScrollingView(View view) {
    
    
        do {
    
    
            ViewParent parent = view.getParent();
            if (parent == null || !(parent instanceof ViewGroup)) {
    
    
                return null;
            }
            ViewGroup parentView = (ViewGroup) parent;
            if (parentView instanceof ScrollingView) {
    
    
                return parentView;
            }
            view = parentView;
        } while (true);
    }
}

猜你喜欢

转载自blog.csdn.net/hegan2010/article/details/113103751
今日推荐