Android之RecyclerView轻松实现下拉刷新和加载更多
今天研究了下RecyclerView的滑动事件,特别是下拉刷新和加载更多事件,在现在几乎所有的APP显示数据列表时都用到了。自定义RecyclerView下拉刷新和加载更多听上去很复杂,实际上并不难,只要是对滑动事件的监听和处理。
一、自定义RecyclerView实现下拉刷新和加载更多
1、如何判断RecyclerView是在上滑还是下滑
在RecyclerView的OnScrollListener滑动事件监听中有个好用的方法,就是onScrolled(RecyclerView recyclerView, int dx, int dy),其中根据dx的值的正负就可以判断是在左滑还是右滑,而根据dy的值就可以判断是在上滑还是下滑。
//上滑
if(dy>0){
//相应操作代码
}
//下滑
else if(dy<0){
//相应操作代码
}
2、如何判断是否滑到了顶部或者底部
同样在RecyclerView的OnScrollListener滑动事件监听中onScrolled(RecyclerView recyclerView, int dx, int dy)方法中处理,根据canScrollVertically(int direction)来进行判断。
//是否滑到底部
if(!recyclerView.canScrollVertically(1)){
//相应处理操作
}
//是否滑到顶部
if(!recyclerView.canScrollVertically(-1)){
//相应处理操作
}
3、自定义RecyclerView
知道了滑动事件的判断和处理,就可以很轻松得实现下拉刷新和加载更多了。
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View; /**
* Package:com.liuting.library
* author:liuting
* Date:2017/2/14
* Desc:自定义RecycleView,下拉刷新以及上拉加载更多
*/ public class RefreshLoadMoreRecycleView extends RecyclerView implements RecyclerView.OnTouchListener{
private Boolean isLoadMore;//加载更多标志
private Boolean isLoadEnd;//加载到最后的标志
private Boolean isLoadStart;//顶部的标志
private Boolean isRefresh;//下拉刷新标志
private int lastVisibleItem;//最后一项
private IOnScrollListener listener;//事件监听
private float mLastY;//监听移动的位置 public RefreshLoadMoreRecycleView(Context context) {
super(context);
init(context);
} public RefreshLoadMoreRecycleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(context);
} public RefreshLoadMoreRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
} /**
* 初始化
*
* @param context
*/
public void init(Context context) {
isLoadEnd=false;
isLoadStart =true; this.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
//SCROLL_STATE_DRAGGING 和 SCROLL_STATE_IDLE 两种效果自己看着来
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
loadData();
}
} @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//上滑
if(dy>0){
//是否滑到底部
if(!recyclerView.canScrollVertically(1)){
isLoadEnd = true;
}else{
isLoadEnd = false;
}
Log.e("TAG","Running--->>isLoadEnd:"+isLoadEnd+dy);
}else if(dy<0){
//是否滑到顶部
if(!recyclerView.canScrollVertically(-1)){
isLoadStart=true;
}else{
isLoadStart=false;
} }
}
});
this.setOnTouchListener(this);
} /**
*
* 加载数据
*
*/
private void loadData() {
if (isLoadEnd) {
// 判断是否已加载所有数据
if (isLoadMore) {//未加载完所有数据,加载数据,并且还原isLoadEnd值为false,重新定位列表底部
if (getListener() != null) {
getListener().onLoadMore();
}
} else {//加载完了所有的数据
if(getListener()!=null){
getListener().onLoaded();
}
}
isLoadEnd = false;
} else if (isLoadStart) {
if(isRefresh){
if (getListener() != null) {
getListener().onRefresh();
}
isLoadStart=false;
}
}
} @Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (mLastY == -1) {
mLastY = motionEvent.getRawY();
}
switch (motionEvent.getAction()){
case MotionEvent.ACTION_MOVE:
final float deltaY = motionEvent.getRawY() - mLastY;
mLastY = motionEvent.getRawY();
//向上移动
if(deltaY<0){
//是否滑到底部
if(!this.canScrollVertically(1)){
isLoadEnd = true;
}else{
isLoadEnd = false;
}
}
//向下移动
else if(deltaY>0) {
//是否滑到顶部
if (!this.canScrollVertically(-1)) {
isLoadStart = true;
} else {
isLoadStart = false;
}
}
break;
case MotionEvent.ACTION_DOWN:
mLastY = motionEvent.getRawY();
break;
default://重置
mLastY = -1;
break;
} return false;
} //事件监听
public interface IOnScrollListener {
void onRefresh(); void onLoadMore(); void onLoaded();
} public IOnScrollListener getListener() {
return listener;
} //设置事件监听
public void setListener(IOnScrollListener listener) {
this.listener = listener;
} public Boolean getLoadMore() {
return isLoadMore;
} //设置是否支持加载更多
public void setLoadMoreEnable(Boolean loadMore) {
isLoadMore = loadMore;
} public Boolean getRefresh() {
return isRefresh;
} //设置是否支持下拉刷新
public void setRefreshEnable(Boolean refresh) {
isRefresh = refresh;
}
}
二、实际用例
已经定义好了RecyclerView,下面在Demo中实际使用和处理。
1、定义布局
布局文件很简单,就是一个RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.liuting.refreshloadmorelistview.MainActivity"> <com.liuting.library.RefreshLoadMoreRecycleView
android:id="@+id/main_recycle_view_data"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
/>
</LinearLayout>
2、定义RecyclerView.Adapter
RecyclerView.Adapter在这里就简单处理了,列表布局直接使用Android自带的。
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView; import java.util.List; /**
* Package:com.liuting.refreshloadmorelistview.adapter
* author:liuting
* Date:2017/2/16
* Desc:列表Adapter
*/ public class RefreshLoadMoreRecycleAdapter extends RecyclerView.Adapter<RefreshLoadMoreRecycleAdapter.ViewHolder> {
private List<String> list;
private Context context; public RefreshLoadMoreRecycleAdapter(Context context,List<String> list) {
this.context =context;
this.list = list;
} @Override
public RefreshLoadMoreRecycleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
RefreshLoadMoreRecycleAdapter.ViewHolder viewHolder = new RefreshLoadMoreRecycleAdapter.ViewHolder(view);
return viewHolder;
} @Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.text.setText(list.get(position));
holder.itemView.setTag(position);
} @Override
public int getItemCount() {
return list.size();
} class ViewHolder extends RecyclerView.ViewHolder{
private TextView text; public ViewHolder(View itemView) {
super(itemView);
text=(TextView)itemView.findViewById(android.R.id.text1);
}
}
}
3、在Activity中定义好控件以及数据加载操作
实现自定义RecyclerView中的数据加载事件监听,刷新、加载更多以及加载完成。
import android.app.ProgressDialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.widget.Toast; import com.liuting.library.RefreshLoadMoreRecycleView;
import com.liuting.refreshloadmorelistview.adapter.RefreshLoadMoreRecycleAdapter; import java.util.ArrayList;
import java.util.List; public class MainActivity extends AppCompatActivity implements RefreshLoadMoreRecycleView.IOnScrollListener{
private RefreshLoadMoreRecycleView recycleView;//下拉刷新RecycleView
private List<String> list;//列表
private RefreshLoadMoreRecycleAdapter adapter;//Adapter
private ProgressDialog dialog;//提示框
private static final int REFRESH_Load=0;//下拉刷新
private static final int MORE_Load=1;//加载更多
private Handler handler =new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case REFRESH_Load:
recycleView.setLoadMoreEnable(true);
dismissDialog();
if(list!=null){
list.clear();
}
loadData();
adapter.notifyDataSetChanged();
break;
case MORE_Load:
recycleView.setLoadMoreEnable(false);
dismissDialog();
loadData();
adapter.notifyDataSetChanged();
break;
}
}
}; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
} public void initView(){
dialog = new ProgressDialog(MainActivity.this); list=new ArrayList<>();
loadData();
recycleView = (RefreshLoadMoreRecycleView)findViewById(R.id.main_recycle_view_data); final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
recycleView.setLayoutManager(linearLayoutManager);
adapter = new RefreshLoadMoreRecycleAdapter(MainActivity.this,list);
recycleView.setAdapter(adapter);
recycleView.setListener(this);
recycleView.setRefreshEnable(true);
recycleView.setLoadMoreEnable(true);
} /**
* 加载数据
*/
public void loadData(){
for(int i=0;i<10;i++ ){
list.add("It is "+i);
}
} @Override
public void onRefresh() {
showDialog();
new Thread(){
@Override
public void run() {
super.run();
try {
sleep(5000);
handler.sendEmptyMessage(REFRESH_Load);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
} @Override
public void onLoadMore() {
showDialog();
new Thread(){
@Override
public void run() {
super.run();
try {
sleep(5000);
handler.sendEmptyMessage(MORE_Load);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
} @Override
public void onLoaded() {
Toast.makeText(MainActivity.this,"Loaded all",Toast.LENGTH_SHORT).show();
} /**
* dismiss dialog
*/
private void dismissDialog(){
if (dialog!=null&&dialog.isShowing()){
dialog.dismiss();
}
} /**
* show dialog
*/
private void showDialog(){
if (dialog!=null&&!dialog.isShowing()){
dialog.show();
}
}
}
三、最终效果图

到这里就轻松实现了RecyclerView的下拉刷新和加载更多了。
源代码放在了Github上:https://github.com/LT5505/RefreshLoadMoreRecycleView
Android之RecyclerView轻松实现下拉刷新和加载更多的更多相关文章
- Android UI--自定义ListView(实现下拉刷新+加载更多)
Android UI--自定义ListView(实现下拉刷新+加载更多) 关于实现ListView下拉刷新和加载更多的实现,我想网上一搜就一堆.不过我就没发现比较实用的,要不就是实现起来太复杂,要不就 ...
- RecyclerView的下拉刷新和加载更多 动画
下拉刷新和加载更多 1.https://github.com/jianghejie/XRecyclerView 2.http://blog.csdn.net/jabony/article/detail ...
- RecyclerView 下拉刷新和加载更多
一.SwipeRefreshLayout实现下拉刷新 1.方法API: setOnRefreshListener(OnRefreshListener):添加下拉刷新监听器 setRefreshing( ...
- 自己封装的工具类,使用原生SwipeRefreshLayout+RecycleView实现下拉刷新和加载更多
实现SwipeRefreshLayout+RecycleView实现刷新 在你的xml文件里写上如下代码: <android.support.v4.widget.SwipeRefreshLayo ...
- iOS 下拉刷新和加载更多 (OC\Swift)
Swift语言出来之后, 可能还没有第三方的下拉刷新和上提加载, 所以自己用UIRefreshControl控件和UITableView实例的tableFooterView(底部视图)属性结合起来写了 ...
- Android Demo 下拉刷新+加载更多+滑动删除
小伙伴们在逛淘宝或者是各种app上,都可以看到这样的功能,下拉刷新和加载更多以及滑动删除,刷新,指刷洗之后使之变新,比喻突破旧的而创造出新的,比如在手机上浏览新闻的时候,使用下拉刷新的功能,我们可以第 ...
- PullToRefresh下拉刷新 加载更多 详解 +示例
常用设置 项目地址:https://github.com/chrisbanes/Android-PullToRefresh a. 设置刷新模式 如果Mode设置成Mode.PULL_FROM_STAR ...
- Android几种强大的下拉刷新库
BeautifulRefreshLayout 众多优秀的下拉刷新(除了我写的之外T_T) 说起下拉刷新,好像经历一段历史的洗礼... (1)在我刚学android的时候,用的是XListView,在g ...
- 【转载】 Android PullToRefresh (ListView GridView 下拉刷新) 使用详解
Android下拉刷新pullToRefreshListViewGridView 转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/3 ...
随机推荐
- FZU 2110 Star
简单暴力题,读入%lld会WA,%I64d能过. #include<cstdio> #include<cstring> #include<cmath> #inclu ...
- Spring学习---JPA学习笔记
用了一段时间的Spring,到现在也只是处于会用的状态,对于深入一点的东西都不太了解.所以决定开始深入学习Spring. 本文主要记录JPA学习.在学习JPA之前,需要了解一些ORM的概念. ORM概 ...
- RDA5820收音机芯片驱动
RDA5820 是北京锐迪科推出的一款集成度非常高的立体声 FM收发芯片.该芯片具有以下 特点: FM 发射和接收一体 支持 65Mhz~115Mhz的全球 FM接收频段,收发天线共用. ...
- Delphi 内存分配 StrAlloc New(转)
源:Delphi 内存分配 StrAlloc New 引自:http://anony3721.blog.163.com/blog/static/5119742010824934164/ 给字符指针 ...
- CSS长度单位详解
序言 长度单位可以总体的分为绝对长度单位和相对长度单位.CSS中最为大家熟知的无疑是px和em,但与此同时还存在pt, rem, vw, vh等其他计量单位,使用好它们可以大大增长我们的开发效率.本篇 ...
- Java中实现Serializable接口为什么要声明serialVersionUID?
什么情况下需要修改serialVersionUID 的值? 序列化运行时使用一个称为 serialVersionUID 的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化 ...
- C#、C++用GDAL读shp文件(转载)
C#.C++用GDAL读shp文件 C#用GDAL读shp文件 (2012-08-14 17:09:45) 标签: 杂谈 分类: c#方面的总结 1.目前使用开发环境为VS2008+GDAL1.81 ...
- XML 字符串解析
微信红包发送完成后返回xml字符串,解析过程如下: 1.调用解析: public ActionResult GetEntityFromXml() { string str = @"<x ...
- CentOS 6.6下JDK1.7安装与配置(Linux)经典入门详解案例
最近用的linux较多,在网站找了一些关于linux环境下jdk安装的教程,过程是有的但是好多细节都没有表现出来,所以我花了点时间总结了一下,希望对大家都有帮助... CentOS下JDK1.7安装与 ...
- #搜索# #BFS# #优先队列# ----- OpenJudge鸣人和佐助
OpenJudge 6044:鸣人和佐助 总时间限制: 1000ms 内存限制: 65536kB 描述 佐助被大蛇丸诱骗走了,鸣人在多少时间内能追上他呢? 已知一张地图(以二维矩阵的形式表示)以及佐 ...