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. vue 单向数据流 & 双向绑定

    在react中是单向数据绑定,而在vue中的特色是双向数据绑定.但是其实就我个人的理解是: 其实无论是vue还是react其实还是提倡单向数据流去管理状态,这一点在vuex和redux状态管理器上体现 ...

  2. hdu-4027线段树练习

    title: hdu-4027线段树练习 date: 2018-10-10 18:07:11 tags: acm 算法 刷题 categories: ACM-线段树 # 概述 这道线段树的题可以说是我 ...

  3. js包

    1.base.js /*语法: $("选择器") 工厂函数 */       /*寻找页面中name属性值是haha的元素*/   $("[name='haha']&qu ...

  4. read()函数的困惑

    #define BUF_SIZE 10 int main() { int cnt; char buf[BUF_SIZE]; cnt = read(STDIN_FILENO, buf, BUF_SIZE ...

  5. 1036 Boys vs Girls (25)(25 point(s))

    problem This time you are asked to tell the difference between the lowest grade of all the male stud ...

  6. CXF发布webservice

    http://wenku.baidu.com/link?url=dTJpXcL0TXslGAYYC6SSOrPGvjyEb974ZGx9-0dymU32YDjxuP8DwlI1sFpPCGqu_ywW ...

  7. parcelable 和 serializable 区别

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha serializable 是 java 中的 序列化 接口. parcelable 是 ...

  8. 希尔排序之Java实现

    希尔排序之Java实现 一.方法一 package cn.com.zfc.lesson21.sort; /** * * @title ShellSort * @describe 希尔排序 1959 年 ...

  9. with在模板中的应用

    var str = 'Hello <%= name %>!'; var o = { name: 'Alice' }; function tmpl(str, obj) { str = 'va ...

  10. 在线HTTP速度测试(响应时间测试)及浏览器兼容测试

    一.前言 网站的响应时间,是判断一个网站是否是好网站的重要的因素之一.百度首页的响应时间在全国各个省份小于10ms.这个响应时间远远好于竞争对手.根据美丽说的技术负责人分析,美丽说访问速度提升10%, ...