RecyclerView 获取滑动停止时展示出的item范围

RecyclerView 获取滑动停止时展示出的item范围

最近做了个需求,需要知道RecyclerView滑动停止后展示出来的Item,正常的线形和网格布局比较正常,我的RecyclerView是瀑布流形式的,所以获取起来稍微有一些不太一样,在这记录一下,免得下次忘了。

主要需要的类 RecyclerView.OnScrollListener

原理其实很简单,只需要在listener中的onScrollStateChanged方法的回调中做一下判断,然后根据LayoutManager即可获得范围,LinearLayoutManger和GridLayoutManager获取方式一样,StaggeredGridLayoutManager有一点点不太一样,具体先放下代码:

private RecyclerView.OnScrollListener listener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if(newState == RecyclerView.SCROLL_STATE_IDLE){
                int[] range = new int[2];
                RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
                if(manager instanceof LinearLayoutManager){
                    range = findRangeLinear((LinearLayoutManager) manager);
                }else if(manager instanceof GridLayoutManager){
                    range = findRangeGrid((GridLayoutManager) manager);
                }else if(manager instanceof StaggeredGridLayoutManager){
                    range = findRangeStaggeredGrid((StaggeredGridLayoutManager) manager);
                }
                Log.d("LOG","range:"+range[0]+"to"+range[1]);
                Toast.makeText(MainActivity.this,"range:"+range[0]+" to"+range[1],Toast.LENGTH_SHORT).show();
            }

        }

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


    private int[] findRangeLinear(LinearLayoutManager manager){
        int[] range = new int[2];
        range[0]=manager.findFirstVisibleItemPosition();
        range[1]=manager.findLastVisibleItemPosition();
        return range;
    }

    private int[] findRangeGrid(GridLayoutManager manager){
        int[] range = new int[2];
        range[0] = manager.findFirstVisibleItemPosition();
        range[1] = manager.findLastVisibleItemPosition();
        return range;

    }

    private int[] findRangeStaggeredGrid(StaggeredGridLayoutManager manager){
        int[] startPos = new int[manager.getSpanCount()];
        int[] endPos = new int[manager.getSpanCount()];
        manager.findFirstVisibleItemPositions(startPos);
        manager.findLastVisibleItemPositions(endPos);
        int[] range = findRange(startPos,endPos);
        return range;
    }

    private int[] findRange(int[] startPos,int[] endPos){
        int start = startPos[0];
        int end = endPos[0];
        for(int i=1;iif(start > startPos[i]){
                start = startPos[i];
            }
        }
        for(int i=1;iif(end < endPos[i]){
                end = endPos[i];
            }
        }
        int[] res = new int[]{start,end};
        return res;
    }

其中StaggeredGridLayoutManager获取的方式不太一样,因为瀑布流的布局方式的特性,假设有左右两列的时候,右侧的列position并不一定会比左右的大,所以StaggeredGridLayoutManager的findFirstVisibleItemPositions方法需要我们传进去一个int类型的数组,数组的大小应该与瀑布流的spanCount相同,该方法实现如下:

public int[] findFirstVisibleItemPositions(int[] into) {
        if (into == null) {
            into = new int[mSpanCount];
        } else if (into.length < mSpanCount) {
            throw new IllegalArgumentException("Provided int[]'s size must be more than or equal"
                    + " to span count. Expected:" + mSpanCount + ", array size:" + into.length);
        }
        for (int i = 0; i < mSpanCount; i++) {
            into[i] = mSpans[i].findFirstVisibleItemPosition();
        }
        return into;
    }

这里可以知道,这个方法会把每一列的第一个可见元素放到数组中,这个传入的数组不能比spanCount小否则会跑出异常,当然这个数组也是可以不传入的,这个函数的@param上写了这么一句:into An array to put the results into. If you don’t provide any, LayoutManager will create a new one.
好了 可以看一下效果了

你可能感兴趣的:(Android)