RecyclerView 判断滑到底部 顶部 预加载 更多 分页 MD
2024-08-26 00:12:44
Markdown版本笔记 | 我的GitHub首页 | 我的博客 | 我的微信 | 我的邮箱 |
---|---|---|---|---|
MyAndroidBlogs | baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
RecyclerView 判断滑到底部 顶部 预加载 更多 分页 MD
目录
目录
项目中的案例【预加载】
项目中的另一个案例
利用 lastVisibleItemPosition 判断【不靠谱】
利用 computeVerticalScrollRange 等判断【不靠谱】
利用 canScrollVertically(direction) 判断【比较靠谱】
利用 LinearLayoutManager 来判断【垃圾】
项目中的案例【预加载】
项目中的另一个案例
利用 lastVisibleItemPosition 判断【不靠谱】
利用 computeVerticalScrollRange 等判断【不靠谱】
利用 canScrollVertically(direction) 判断【比较靠谱】
利用 LinearLayoutManager 来判断【垃圾】
判断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 判断【不靠谱】
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
最新文章
- intellij idea 12 编码不可映射字符
- EUI ViewStack实现选项卡组件
- 基于ruby的watir自动化测试 笔记一
- 63.Hbase 常用命令
- [转]ACM进阶计划
- JS匿名函数的理解
- Android与后台数据交互学习
- [ZT] 酒店大洗脑:最全各大国际酒店集团族谱图
- SPRING IN ACTION 第4版笔记-第一章-002-DI介绍
- Java GC专家系列2:Java 垃圾回收的监控
- C#扩展方法的理解 (转)
- 从用eclipse还是idea所想到的
- ORACLE设置自启动记录
- volatile适用场合
- Java公开课-03.内部类
- 电脑获取手机文件的一种方式(通过手机建立ftp)
- FloatingActionButton(悬浮按钮)使用学习<;一>;
- 怎么理解Python画图中的X,y
- elasticsearch命令
- 用html+css做机器猫 源代码
热门文章
- Python并发编程系列之常用概念剖析:并行 串行 并发 同步 异步 阻塞 非阻塞 进程 线程 协程
- 标准c库函数与Linux下系统函数库 区别 (即带不带缓冲区的学习)
- Django Q对象
- bzoj5102 [POI2018]Prawnicy 线段树
- CF1027F Session in BSU
- [Visual Studio] VS2012调试时很慢的解决方案
- LAMP架构之NFS
- 一个.net下的轻量级的Serverless 文档数据库LiteDB
- OllyDbg 使用笔记 (十二)
- authentication not supported Connect to TFS Git from Xamarin Studio (non-hosted, locally installed TFS 2013)