Layout manager that supports NestedScrollView and RecyclerView nested double sliding

NestedScrollView and RecyclerView nested use problems, what I saw on the Internet is to set setNestedScrollingEnabled(false) for RecyclerView. But there is a problem with this method,
that is, the height of RecyclerView is required to be wrap_content (otherwise the height is too small, and the Item View at the bottom cannot slide out), that is, how many Item Views there are, there must be a corresponding height. But this is not what I want. First, this will cause the ViewHolder to not be recycled! ! ! RecyclerView loses the meaning of Recycle! ! ! The second is that the overall sliding effect is inconsistent when quickly fling sliding to the top. Some people call this method elegant, but it's not elegant at all. . .

Take a look at the video to see what the effects are before and after use:

before

after

(Original work, please state the source for reprinting: https://blog.csdn.net/hegan2010/article/details/113103751 )

In order to solve this problem, the NestedScrollView and RecyclerView can be double-slid without sliding conflict, and a layout manager is written.
The principle is that when the top of the visible area of ​​RecyclerView is lower than the top of the visible area of ​​NestedScrollView, reduce the sliding distance consumed by RecyclerView on the Y axis, or set it to 0, or the difference in height between the two, so that NestedScrollView consumes more sliding distance .

The implementation code is as follows (inherited from GridLayoutManager, which can be modified to which LayoutManager is inherited from according to the actual situation, as long as the scrollVerticallyBy method is overloaded):

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

Guess you like

Origin blog.csdn.net/hegan2010/article/details/113103751
Recommended