Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱
MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina.com

RecyclerView 判断滑到底部 顶部 预加载 更多 分页 MD


目录

判断RecyclerView到达底部的几种方法

项目中的案例【预加载】

mRvChat.addOnScrollListener(new RecyclerView.OnScrollListener() {
private int minLeftItemCount=10;//剩余多少条时开始加载更多
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int itemCount = layoutManager.getItemCount();
int lastPosition = layoutManager.findLastCompletelyVisibleItemPosition();
XLog.tag("bqt3").i("【总数】" + itemCount + "【位置】" + lastPosition);
if (lastPosition == layoutManager.getItemCount() - 1) {//容错处理,保证滑到最后一条时一定可以加载更多
this.onLoadMore();
} else {
if (itemCount > minLeftItemCount) {
if (lastPosition == itemCount - minLeftItemCount) {
//一定要意识到,onScrolled方法并不是一直被回调的,估计最多一秒钟几十次
//所以当此条件满足时,可能并没有回调onScrolled方法,也就不会调用onLoadMore方法
//所以一定要想办法弥补这隐藏的bug,最简单的方式就是当滑到最后一条时一定可以加载更多
this.onLoadMore();
}
} else {//(第一次进入时)如果总数特别少,直接加载更多
this.onLoadMore();
}
}
}
}
private void onLoadMore() {
if (canLoadMore) {
canLoadMore = false;
ChatReqHelper.requestGroupHis(groupId, ((ChatModel) mGroupChats.get(mGroupChats.size() - 1)).getMsgId());
XLog.tag("bqt3").i("【加载更多数据】");
}
}
});

项目中的另一个案例

rv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) rv.getLayoutManager();
int[] positions = layoutManager.findLastVisibleItemPositions(null);
if (positions != null && positions.length > 0) {
for (int position : positions) {
if (position >= mDatas.size() - layoutManager.getSpanCount() || !rv.canScrollVertically(1)) {//滑到底部了
if (canLoadMore) {
XLog.tag("bqt_red").i("加载更多 "+position+" "+rv.canScrollVertically(1));
canLoadMore = false;
doRequest();
}
break;
}
}
}
}
});

利用 lastVisibleItemPosition 判断【不靠谱】

简单判断

public static boolean isVisBottom(RecyclerView recyclerView){
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int lastVisibleItemPosition = layoutManager.findLastVisibleItemPosition(); //屏幕中最后一个可见子项的position
int visibleItemCount = layoutManager.getChildCount(); //当前屏幕所看到的子项个数
int totalItemCount = layoutManager.getItemCount(); //当前RecyclerView的所有子项个数
int state = recyclerView.getScrollState(); //RecyclerView的滑动状态
if(visibleItemCount > 0 && lastVisibleItemPosition == totalItemCount - 1 && state == recyclerView.SCROLL_STATE_IDLE){
return true;
}else {
return false;
}
}

当屏幕中最后一个子项 lastVisibleItemPosition 等于所有子项个数 totalItemCount - 1,那么RecyclerView就到达了底部。

但是,如果 totalItemCount 等于1,并且这个item的高度比屏幕还要高时,我们可以发现这个item没完全显示出来就已经被判断为拉到底部。

利用 computeVerticalScrollRange 等判断【不靠谱】

这种方法原理其实很简单,而且也是View自带的方法

public static boolean isSlideToBottom(RecyclerView recyclerView) {
return recyclerView != null
&& recyclerView.computeVerticalScrollExtent()//当前屏幕显示区域的高度
+ recyclerView.computeVerticalScrollOffset()//当前屏幕之前滑过的距离
>= recyclerView.computeVerticalScrollRange();//整个View控件的高度
}

这种方法经过测试,暂时还没发现有bug,而且它用的是View自带的方法,所以个人觉得比较靠谱。

利用 canScrollVertically(direction) 判断【比较靠谱】

这种方法更简单,就通过简单的调用方法,就可以得到你想要的结果。

这种方法与第二种方法其实是同一种方法,我们看看 canScrollVertically 的源码:

/**
* Check if this view can be scrolled vertically in a certain direction.
*
* @param direction Negative to check scrolling up, positive to check scrolling down.
* @return true if this view can be scrolled in the specified direction, false otherwise.
*/
public boolean canScrollVertically(int direction) {
final int offset = computeVerticalScrollOffset();
final int range = computeVerticalScrollRange() - computeVerticalScrollExtent();
if (range == 0) return false;
if (direction < 0) {
return offset > 0;
} else {
return offset < range - 1;
}
}

canScrollVertically(1)的值表示是否能向上滚动,true表示能滚动,false表示已经滚动到底部

canScrollVertically(-1)的值表示是否能向下滚动,true表示能滚动,false表示已经滚动到顶部

利用 LinearLayoutManager 来判断【垃圾】

这种方法其实是比较呆板的,就是利用LinearLayoutManager的几个方法算出已经滑过的子项的距离、屏幕的高度、RecyclerView的总高度,最后将高度作比较。

  • 算出一个子项的高度
public static int getItemHeight(RecyclerView recyclerView) {
int itemHeight = 0;
View child = null;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstPos = layoutManager.findFirstCompletelyVisibleItemPosition();
int lastPos = layoutManager.findLastCompletelyVisibleItemPosition();
child = layoutManager.findViewByPosition(lastPos);
if (child != null) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
itemHeight = child.getHeight() + params.topMargin + params.bottomMargin;
}
return itemHeight;
}
  • 算出滑过的子项的总距离
public static int getLinearTotalHeight(RecyclerView recyclerView) {
int totalHeight = 0;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
View child = layoutManager.findViewByPosition(layoutManager.findFirstVisibleItemPosition());
int headerCildHeight = getHeaderHeight(recyclerView);
if (child != null) {
int itemHeight = getItemHeight(recyclerView);
int childCount = layoutManager.getItemCount();
totalHeight = headerCildHeight + (childCount - 1) * itemHeight;
}
return totalHeight;
}
  • 算出所有子项的总高度
public static boolean isLinearBottom(RecyclerView recyclerView) {
boolean isBottom = true;
int scrollY = getLinearScrollY(recyclerView);
int totalHeight = getLinearTotalHeight(recyclerView);
int height = recyclerView.getHeight();
// Log.e("height","scrollY " + scrollY + " totalHeight " + totalHeight + " recyclerHeight " + height);
if (scrollY + height < totalHeight) {
isBottom = false;
}
return isBottom;
}
  • 其他逻辑
public static int getHeaderHeight(RecyclerView recyclerView) {
int headerCildHeight = 0; LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int firstHeaderPos = layoutManager.findFirstCompletelyVisibleItemPosition();
View headerCild = layoutManager.findViewByPosition(firstHeaderPos); if (headerCild != null) {
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) headerCild.getLayoutParams();
headerCildHeight = headerCild.getHeight() + params.topMargin + params.bottomMargin;
}
return headerCildHeight;
}
public static int getLinearScrollY(RecyclerView recyclerView) {
int scrollY = 0;
LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int headerCildHeight = getHeaderHeight(recyclerView);
int firstPos = layoutManager.findFirstVisibleItemPosition();
View child = layoutManager.findViewByPosition(firstPos);
int itemHeight = getItemHeight(recyclerView);
if (child != null) {
int firstItemBottom = layoutManager.getDecoratedBottom(child);
scrollY = headerCildHeight + itemHeight * firstPos - firstItemBottom;
if (scrollY < 0) {
scrollY = 0;
}
} return scrollY;
}

虽然这种方法看上去比较呆板的同时考虑不很周全,但这种方法可以对RecylerView的LinearLayoutManager有深一步的理解!

2017.06.23

RecyclerView 判断滑到底部 顶部 预加载 更多 分页 MD的更多相关文章

  1. 手把手教你实现RecyclerView的下拉刷新和上拉加载更多

    手把手教你实现RecyclerView的下拉刷新和上拉加载更多     版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...

  2. Android RecyclerView 瀑布流滑动到最后自动加载更多

    mRecycleView.setOnScrollListener(new RecyclerView.OnScrollListener(){ //用来标记是否正在向最后一个滑动,既是否向下滑动 bool ...

  3. Vue——轻松实现vue底部点击加载更多

    前言 需求总是不断改变的,好吧,今天就把vue如何实现逐步加载更多和分布加载更多说下,默认你知道如何去请求数据的哈 一次请求 页面 使用slice来进行限制展现从0,a的数据 <div v-fo ...

  4. 关于H5判定区域里面滑动到底部,加载更多的总结

    1.如何判定H5中滑动到底部,然后加载更多的功能实现. 思路:我们需要设定一个固定高度的盒子,然后我们利用scroll来监听滚动,当scrollTop(滚动的距离) + clientHeight(页面 ...

  5. 实现上拉加载更多的SwipeRefreshLayout

    转载请标明出处: http://blog.csdn.net/developer_jiangqq/article/details/49992269 本文出自:[江清清的博客] (一).前言: [好消息] ...

  6. google官方的下拉刷新+自定义上拉加载更多

    转载请标注转载:http://blog.csdn.net/oqihaogongyuan/article/details/50949118 google官方的下拉刷新+自定义上拉加载更多 现在很多app ...

  7. vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件

    1.下拉刷新和上拉加载更多组件 Scroller.vue <!-- 下拉刷新 上拉加载更多 组件 --> <template> <div :style="mar ...

  8. Vue.js 开发实践:实现精巧的无限加载与分页功能

    本篇文章是一篇Vue.js的教程,目标在于用一种常见的业务场景--分页/无限加载,帮助读者更好的理解Vue.js中的一些设计思想.与许多Todo List类的入门教程相比,更全面的展示使用Vue.js ...

  9. nodejs爬虫笔记(四)---利用nightmare解决加载更多问题

    目标: 解决页面加载更多问题.笔记三中,我们只爬取到网页的部分信息,而点击加载更多后的页面内容是没有提取到的.开始我的想法是找到加载更多的数据接口(可参照:http://www.jianshu.com ...

随机推荐

  1. 深度学习基础系列(五)| 深入理解交叉熵函数及其在tensorflow和keras中的实现

    在统计学中,损失函数是一种衡量损失和错误(这种损失与“错误地”估计有关,如费用或者设备的损失)程度的函数.假设某样本的实际输出为a,而预计的输出为y,则y与a之间存在偏差,深度学习的目的即是通过不断地 ...

  2. C++运算符重载 模板友元 new delete ++ = +=

    今天的重载是基于C++ 类模板的,如果需要非类模板的重载的朋友可以把类模板拿掉,同样可以参考,谢谢. 一.类模板中的友元重载 本人喜好类声明与类成员实现分开写的代码风格,如若您喜欢将类成员函数的实现写 ...

  3. 【洛谷】2473:[SCOI2008]奖励关【期望DP(倒推)】

    P2473 [SCOI2008]奖励关 题目背景 08四川NOI省选 题目描述 你正在玩你最喜欢的电子游戏,并且刚刚进入一个奖励关.在这个奖励关里,系统将依次随机抛出k次宝物,每次你都可以选择吃或者不 ...

  4. Codeforces Round #294 (Div. 2)D - A and B and Interesting Substrings 字符串

    D. A and B and Interesting Substrings time limit per test 2 seconds memory limit per test 256 megaby ...

  5. X-010 FriendlyARM tiny4412 uboot移植之移植网卡驱动TFTP用起来

    <<<<<<<<<<<<<<<<<<<<<<<<< ...

  6. php-curl小记

    用jQuery: $.ajax({ url:url, type:"POST", data:data, contentType:"application/json; cha ...

  7. android WebView中js的alert()失效

    WebView的设置代码 wv = (WebView) findViewById(R.id.webView1); wv.getSettings().setJavaScriptEnabled(true) ...

  8. sqlserver存储过程循环写法

    用游标,和WHILE可以遍历您的查询中的每一条记录并将要求的字段传给变量进行相应的处理==================DECLARE @A1 VARCHAR(10),@A2 VARCHAR(10) ...

  9. WINDOWS WPA性能分析

    http://r12f.com/posts/introduction-to-wpa-1-why-it-is-slow/ http://www.freebuf.com/column/138862.htm ...

  10. cmake和make区别

    大家都知道,写程序大体步骤为: 1.用编辑器编写源代码,如.c文件. 2.用编译器编译代码生成目标文件,如.o. 3.用链接器连接目标代码生成可执行文件,如.exe. 但如果源文件太多,一个一个编译时 ...