最近做了个需求,需要知道RecyclerView滑动停止后展示出来的Item,正常的线形和网格布局比较正常,我的RecyclerView是瀑布流形式的,所以获取起来稍微有一些不太一样,在这记录一下,免得下次忘了。
原理其实很简单,只需要在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.
好了 可以看一下效果了