详解RecyclerView下拉刷新与上拉更多
前言
在原来的文章中我提及了如何使用RecyclerView添加header与footer,今天我们来更深入的扩展一下使用RecyclerView实现常用的下拉刷新与上拉加载更多的功能。当然这些功能的实现也是基于前面的RecyclerView添加header与footer为基础来实现的,不是很了解的可以先看看前面的文章可能能更好的帮助理解。
依赖
为了方法大家的使用我已经把他上传到Jcenter中了,所以大家可以调用下面的代码了直接获取使用:
compile com.idisfkj.enchancerecyclerview:mylibrary:1.1.1
EnhanceRecyclerView
我将这个扩展的RecyclerView命名为EnhanceRecyclerView,继承RecyclerView。我们知道既然要实现下拉刷新与上拉更多自然先要实现头部与尾部的布局,所以我们先利用前面的知识来为EnhanceRecycleView添加header与footer
public void initView() { View headerView = LayoutInflater.from(getContext()).inflate(R.layout.head_layout, null); View footerView = LayoutInflater.from(getContext()).inflate(R.layout.footer_layout, null); addHeaderView(headerView); addFooterView(footerView); }
其中的布局文件就不多说了,至于addHeaderView与addFooterView方法可以查看我前面的那篇文章,有详细的介绍
设置监听器
既然要实现下拉刷新与上拉加载,自然少不了对监听器的处理,所以下面来详细介绍下对监听器OnScrollListener与OnTouchListener的处理。
OnScrollListener
为EnhanceRecyclerView添加addOnScrollListener实现其中的onScrollStateChanged与onScrolled方法。
onScrolled
在onScrolled中我们主要做的是获取EnhanceRcyclerView中item的总数量、视图显示中的第一个item在EnhanceRecyclerView中所处的位置与视图显示中最后一个item在EnhanceRecyclerView中所处的位置。
对于item的总数量很好获取直接调用
totalCount = getLayoutManager().getItemCount();
由于RecyclerView能实现LinearLayoutManager、GridLayoutManager与StaggeredGridLayoutManager不同的布局,所以另外两个要根据不同的manager来获取,还是看具体代码吧
if (getLayoutManager() instanceof LinearLayoutManager) { lastItem = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition(); firstVisible = ((LinearLayoutManager) getLayoutManager()).findFirstVisibleItemPosition(); } else { into = ((StaggeredGridLayoutManager) getLayoutManager()).findLastVisibleItemPositions(into); firstInto = ((StaggeredGridLayoutManager) getLayoutManager()).findFirstVisibleItemPositions(firstInto); lastItem = into[0]; firstVisible = firstInto[0]; }
onScrollStateChanged
获取到了那三个关键数据以后,就可以在onScrollStateChanged中实现具体的逻辑,在这个方法中主要实现的是对上拉加载更多的处理
if (lastItem == adapter.getItemCount() + 1 newState == RecyclerView.SCROLL_STATE_IDLE !isLoad) { ViewGroup.LayoutParams params = getFooterView(0).getLayoutParams(); params.width = RecyclerView.LayoutParams.MATCH_PARENT; params.height = RecyclerView.LayoutParams.WRAP_CONTENT; getFooterView(0).setLayoutParams(params); getFooterView(0).setVisibility(View.VISIBLE); smoothScrollToPosition(totalCount); isLoad = true; loadMoreListener.onLoadMore(); } if (firstVisible == 0) { isTop = true; } else { isTop = false; RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); params.width = RecyclerView.LayoutParams.MATCH_PARENT; params.height = RecyclerView.LayoutParams.WRAP_CONTENT; params.setMargins(0, -getHeaderView(0).getHeight(), 0, 0); getHeaderView(0).setLayoutParams(params); }
简单说明下,核心就是判断lastItem是否处在最后的位置,如果是的话就继续加载更多的操作,这里提供了一个对数据处理的接口所以只要实现loadMoreListener.onLoadMore();即可。
上拉加载更多核心就是这么多,其它的可以查看源码
OnTouchListener
这个监听器主要是对下拉刷新进行处理。我们要分别对其中我们所熟悉的MotionEvent.ACTION_DOWN、MotionEvent.ACTION_MOVE与MotionEvent.ACTION_UP进行处理。ACTION_DOWN就是简单的获取按下的坐标位置,这里就不多说了,下面主要的针对另外的两个进行简单说明。
ACTION_MOVE
这做的逻辑就是对触摸后的处理,根据滑动的距离来动态的改变header的文本与布局视图的显示。
if (getHeaderView(0).getVisibility() == GONE) getHeaderView(0).setVisibility(VISIBLE); RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); params.width = RecyclerView.LayoutParams.MATCH_PARENT; params.height = RecyclerView.LayoutParams.WRAP_CONTENT; //使header随moveY的值从顶部渐渐出现 if (moveY = 400) { moveY = 100 + moveY / 4; } else { moveY = moveY / 2; } viewHeight = getHeaderView(0).getHeight(); if (viewHeight = 0) viewHeight = 130; moveY = moveY - viewHeight; params.setMargins(0, (int) moveY, 0, 0); getHeaderView(0).setLayoutParams(params); if (moveY 80) { text.setText(getResources().getString(R.string.release_to_refresh)); } else { text.setText(getResources().getString(R.string.pull_to_refresh)); } } else { if (getHeaderView(0).getVisibility() != GONE !isRefreshing) { getHeaderView(0).setVisibility(GONE); } } }
至于下拉时与顶部的距离变化是通过设置margin来动态改变的。
ACTION_UP
最后的触摸处理就是在离开屏幕时根据滑动的距离,是否调用加载数据的接口,或者隐藏下拉刷新头部,具体还是看代码吧。
RecyclerView.LayoutParams params1 = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); params1.width = RecyclerView.LayoutParams.MATCH_PARENT; params1.height = RecyclerView.LayoutParams.WRAP_CONTENT; if (moveY = 80) { text.setText(getResources().getString(R.string.refreshing)); params1.setMargins(0, 0, 0, 0); isRefreshing = true; //刷新数据 pullToRefresh.onRefreshing(); } else { if (viewHeight = 0) viewHeight = 130; params1.setMargins(0, -viewHeight, 0, 0); getHeaderView(0).setVisibility(GONE); } getHeaderView(0).setLayoutParams(params1); } }
代码中重要的地方都有指出相信都能看懂,这样下拉与上拉的逻辑就基本实现了,下面来看接口的设计吧
下拉与上拉接口
public void setPullToRefreshListener(PullToRefreshListener pullToRefresh) { if (loadMoreListener == null) { initListener(); } this.pullToRefresh = pullToRefresh; } public interface LoadMoreListener { void onLoadMore(); } public void setLoadMoreListener(LoadMoreListener loadMoreListener) { if (pullToRefresh == null) { initListener(); } this.loadMoreListener = loadMoreListener; }
在运用是添加接口监听时初始化前面为EnhanceRecyclerView所设置的监听。
状态重置设置
在调用下拉刷新或者上拉加载更多之后,我们为其构造通用方法实现,状态的重置与数据的更新,方便统一调用。
public void setLoadMoreComplete() { RecyclerView.LayoutParams params = (LayoutParams) getFooterView(0).getLayoutParams(); params.width = 0; params.height = 0; getFooterView(0).setLayoutParams(params); getFooterView(0).setVisibility(View.GONE); this.getAdapter().notifyDataSetChanged(); isLoad = false; } public void setRefreshComplete() { RecyclerView.LayoutParams params1 = (RecyclerView.LayoutParams) getHeaderView(0).getLayoutParams(); params1.width = RecyclerView.LayoutParams.MATCH_PARENT; params1.height = RecyclerView.LayoutParams.WRAP_CONTENT; params1.setMargins(0, -getHeaderView(0).getHeight(), 0, 0); getHeaderView(0).setLayoutParams(params1); getHeaderView(0).setVisibility(GONE); this.getAdapter().notifyDataSetChanged(); isRefreshing = false; }
所用工作已经完成下面来做个调用示范
使用
xml中引用
com.idisfkj.mylibrary.EnhanceRecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="match_parent" /com.idisfkj.mylibrary.EnhanceRecyclerView
设置监听
mRecyclerView.setPullToRefreshListener(new com.idisfkj.mylibrary.EnhanceRecyclerView.PullToRefreshListener() { @Override public void onRefreshing() { refreshData(); } }); mRecyclerView.setLoadMoreListener(new EnhanceRecyclerView.LoadMoreListener() { @Override public void onLoadMore() { loadMoreData(); } });
refreshData()与loadMoreData()加载数据的逻辑就不展示了,只是要记住在请求网络数据完之后要在他们中调用相应的mRecyclerView.setRefreshComplete()与 mRecyclerView.setLoadMoreComplete()来重置状态。
至于其他的Adapter、LayoutManager等的设置就不多说了,与原生的RecyclerView是一样的。
总结
其实总的来说难点有两个
添加header与footer。这个前面已经攻克了,而且原理也相对简单
实现触摸与滑动监听逻辑。这个主要是对逻辑的理解,对整个刷新的过程做个整体分析,就能很好的理解上面的代码。对其中视图的动态显示做相应的变化与接口的调用就能很好的处理这些工程。
当然上面的实现可能还有瑕疵,希望指出,我会相应的做修改或者你们修改后可以提交给我,我统一做修改,谢谢!
作者:idisfkj
来源:51CTO
为RecyclerView添加下拉刷新功能 在之前的文章中,我们实现了带有header和footer功能的WrapRecyclerView。 现今App中列表的下拉刷新和上拉加载已经是一种习惯了,这两个操作也确实方便很多。 为RecyclerView添加这个功能可以通过多种方法,这里我选用了一种简单的做法。基于pulltorefresh这个库。
Android RecyclerView滑动到底部/上拉/上拉见底自动加载更多实现以及点击/长按事件处理 Android RecyclerView下拉加载更多有Android谷歌官方的实现,实现的方式是通过SwipeRefreshLayout把RecyclerView包裹起来,然后就可以通过SwipeRefreshLayout的回调接口实现下拉刷新功能。
之前在《一步步打造自己的通用上拉加载布局》(如果没有看过,建议先看下这一篇)写到如何实现一个通用的上拉加载布局,本文将基于此进行扩展,实现 RecyclerView 的上拉加载及自动加载。
RecyclerView的下拉刷新和加载更多 动画 下拉刷新和加载更多 1、https://github.com/jianghejie/XRecyclerView 2、http://blog.csdn.net/jabony/article/details/44780187 1、https://github.
SwipeRefreshLayout作为官方的下拉刷新控件,简洁美观的风格使其广泛应用在项目中。美中不足的是SwipeRefreshLayout缺少上拉加载的效果,今天结合RecyclerView实现一个支持下拉刷新与上拉加载的SwipeRefreshLayout。
相关文章
- 【EXCEL】详解使用python读写EXCEL文件(xlrd,xlwt)
- JavaScript中this绑定详解
- Android系统应用开发实战详解
- 【CSDN编程竞赛:第33期】题目详解和源代码实现 2023.3.1
- 详解Tomcat线程池原理及参数释义
- Mysql Explain 详解
- redis-12 缓存雪崩、穿透和击穿详解
- mysql8.0安装详解
- struts2系列(三):struts2配置详解
- [WCF权限控制]WCF自定义授权体系详解[实例篇]
- sed命令详解
- xargs命令详解
- [volatile]关键字和wait()notify()详解
- 详解Vue路由钩子及应用场景
- React Native 控件之 Modal 详解 - Android/iOS 双平台通用
- [ 云原生之谜 ] 云原生背景 && 定义 && 相关技术详解?