Android使用LayoutManager的findFirstCompletelyVisibleItemPosition和findLastCompletelyVisibleItemPosition判断下拉刷新上拉加载问题
Android现在的上拉刷新、下拉加载很多都是使用SwipeRefreshLayout和RecyclerView,监听滑动实现的,在监听滑动时通过标题的两个方法判断是否滑动到底以及是否滑动到头,关于这个网上博客很多,就不介绍了。
一般情况下确实是没有问题的,但是如果你的第一个Item/最后一个Item的View大小超过屏幕大小,你就会发现下拉刷新/上拉加载失去作用。那这是什么问题呢?
首先,我们来看下findFirstCompletelyVisibleItemPosition()
public int findLastCompletelyVisibleItemPosition() {
final View child = findOneVisibleChild(getChildCount() - 1, -1, true, false);
return child == null ? NO_POSITION : getPosition(child);
}
我们看到它是通过findOneVisibleChild()方法来获得View的

可以发现通过findFirstCompletelyVisibleItemPosition()和findLastCompletelyVisibleItemPosition()实现上拉加载下拉刷新并不是很合适,这两个方法如其名,返回的是完全显示的item位置,而不是我们需要的最后一个且底部完全显示的item位置。知道了这个解决方法就简单了。我们只需要修改LinearLayoutManager添加几个方法就好了。
修改的代码如下
public int findFirstTopCompletelyEmergedItemPosition() {
final View child = findOneBorderCompleteVisibleChild(getChildCount() - 1, -1, false);
return child == null ? -1 : getPosition(child);
}
public int findLastBottomCompletelyEmergedItemPosition() {
final View child = findOneBorderCompleteVisibleChild(0, getChildCount(), true);
return child == null ? -1 : getPosition(child);
}
private View findOneBorderCompleteVisibleChild(int fromIndex, int toIndex, boolean requestTop) {
final int start = getStartAfterPadding();
final int end = getEndAfterPadding();
final int next = toIndex > fromIndex ? 1 : -1;
for (int i = fromIndex; i != toIndex; i+=next) {
final View child = getChildAt(i);
final int childStart = getDecoratedStart(child);
final int childEnd = getDecoratedEnd(child);
if (childStart < end && childEnd > start) {
if (requestTop) {
if (childStart >= start) {
return child;
}
} else if (childEnd <= end) {
return child;
}
}
}
return null;
}
当然我这只是是针对LinearLayoutManger,gravity是竖直的情况进行讨论的,其他情况也可以用类似解决方法,有空封装几个通用的类。
浙公网安备 33010602011771号