Android之RecyclerView轻松实现下拉刷新和加载更多

 今天研究了下RecyclerView的滑动事件,特别是下拉刷新和加载更多事件,在现在几乎所有的APP显示数据列表时都用到了。自定义RecyclerView下拉刷新和加载更多听上去很复杂,实际上并不难,只要是对滑动事件的监听和处理。

一、自定义RecyclerView实现下拉刷新和加载更多

1、如何判断RecyclerView是在上滑还是下滑

在RecyclerView的OnScrollListener滑动事件监听中有个好用的方法,就是onScrolled(RecyclerView recyclerView, int dx, int dy),其中根据dx的值的正负就可以判断是在左滑还是右滑,而根据dy的值就可以判断是在上滑还是下滑。

1 //上滑
2 if(dy>0){
3 //相应操作代码
4 }
5 //下滑
6 else if(dy<0){
7 //相应操作代码
8 }

2、如何判断是否滑到了顶部或者底部

同样在RecyclerView的OnScrollListener滑动事件监听中onScrolled(RecyclerView recyclerView, int dx, int dy)方法中处理,根据canScrollVertically(int direction)来进行判断。

1 //是否滑到底部
2 if(!recyclerView.canScrollVertically(1)){
3     //相应处理操作
4 }
5 //是否滑到顶部
6 if(!recyclerView.canScrollVertically(-1)){
7     //相应处理操作
8 }

3、自定义RecyclerView

知道了滑动事件的判断和处理,就可以很轻松得实现下拉刷新和加载更多了。

 

  1 import android.content.Context;
  2 import android.support.annotation.Nullable;
  3 import android.support.v7.widget.RecyclerView;
  4 import android.util.AttributeSet;
  5 import android.util.Log;
  6 import android.view.MotionEvent;
  7 import android.view.View;
  8 
  9 /**
 10  * Package:com.liuting.library
 11  * author:liuting
 12  * Date:2017/2/14
 13  * Desc:自定义RecycleView,下拉刷新以及上拉加载更多
 14  */
 15 
 16 public class RefreshLoadMoreRecycleView extends RecyclerView implements RecyclerView.OnTouchListener{
 17     private Boolean isLoadMore;//加载更多标志
 18     private Boolean isLoadEnd;//加载到最后的标志
 19     private Boolean isLoadStart;//顶部的标志
 20     private Boolean isRefresh;//下拉刷新标志
 21     private int lastVisibleItem;//最后一项
 22     private IOnScrollListener listener;//事件监听
 23     private float mLastY;//监听移动的位置
 24 
 25     public RefreshLoadMoreRecycleView(Context context) {
 26         super(context);
 27         init(context);
 28     }
 29 
 30     public RefreshLoadMoreRecycleView(Context context, @Nullable AttributeSet attrs) {
 31         super(context, attrs);
 32         init(context);
 33     }
 34 
 35     public RefreshLoadMoreRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
 36         super(context, attrs, defStyle);
 37         init(context);
 38     }
 39 
 40      /**
 41      * 初始化
 42      * 
 43      * @param context
 44      */
 45     public void init(Context context) {
 46         isLoadEnd=false;
 47         isLoadStart =true;
 48 
 49         this.addOnScrollListener(new RecyclerView.OnScrollListener() {
 50             @Override
 51             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
 52                 super.onScrollStateChanged(recyclerView, newState);
 53                 //SCROLL_STATE_DRAGGING  和   SCROLL_STATE_IDLE 两种效果自己看着来
 54                 if (newState == RecyclerView.SCROLL_STATE_IDLE) {
 55                     loadData();
 56                 }
 57             }
 58 
 59             @Override
 60             public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
 61                 super.onScrolled(recyclerView, dx, dy);
 62                 //上滑
 63                 if(dy>0){
 64                     //是否滑到底部
 65                     if(!recyclerView.canScrollVertically(1)){
 66                         isLoadEnd = true;
 67                     }else{
 68                         isLoadEnd = false;
 69                     }
 70                     Log.e("TAG","Running--->>isLoadEnd:"+isLoadEnd+dy);
 71                 }else if(dy<0){
 72                     //是否滑到顶部
 73                     if(!recyclerView.canScrollVertically(-1)){
 74                         isLoadStart=true;
 75                     }else{
 76                         isLoadStart=false;
 77                     }
 78 
 79                 }
 80             }
 81         });
 82         this.setOnTouchListener(this);
 83     }
 84 
 85      /**
 86      * 
 87      * 加载数据
 88      * 
 89      */
 90     private void loadData() {
 91         if (isLoadEnd) {
 92             // 判断是否已加载所有数据
 93             if (isLoadMore) {//未加载完所有数据,加载数据,并且还原isLoadEnd值为false,重新定位列表底部
 94                 if (getListener() != null) {
 95                     getListener().onLoadMore();
 96                 }
 97             } else {//加载完了所有的数据
 98                 if(getListener()!=null){
 99                     getListener().onLoaded();
100                 }
101             }
102             isLoadEnd = false;
103         } else if (isLoadStart) {
104             if(isRefresh){
105                 if (getListener() != null) {
106                     getListener().onRefresh();
107                 }
108                 isLoadStart=false;
109             }
110         }
111     }
112 
113     @Override
114     public boolean onTouch(View view, MotionEvent motionEvent) {
115         if (mLastY == -1) {
116             mLastY = motionEvent.getRawY();
117         }
118         switch (motionEvent.getAction()){
119             case MotionEvent.ACTION_MOVE:
120                 final float deltaY = motionEvent.getRawY() - mLastY;
121                 mLastY = motionEvent.getRawY();
122                 //向上移动
123                 if(deltaY<0){
124                     //是否滑到底部
125                     if(!this.canScrollVertically(1)){
126                         isLoadEnd = true;
127                     }else{
128                         isLoadEnd = false;
129                     }
130                 }
131                 //向下移动
132                 else if(deltaY>0) {
133                     //是否滑到顶部
134                     if (!this.canScrollVertically(-1)) {
135                         isLoadStart = true;
136                     } else {
137                         isLoadStart = false;
138                     }
139                 }
140                 break;
141             case MotionEvent.ACTION_DOWN:
142                 mLastY = motionEvent.getRawY();
143                 break;
144             default://重置
145                 mLastY = -1;
146                 break;
147         }
148 
149         return false;
150     }
151 
152     //事件监听
153     public interface IOnScrollListener {
154         void onRefresh();
155 
156         void onLoadMore();
157 
158         void onLoaded();
159     }
160 
161     public IOnScrollListener getListener() {
162         return listener;
163     }
164 
165     //设置事件监听
166     public void setListener(IOnScrollListener listener) {
167         this.listener = listener;
168     }
169 
170     public Boolean getLoadMore() {
171         return isLoadMore;
172     }
173 
174     //设置是否支持加载更多
175     public void setLoadMoreEnable(Boolean loadMore) {
176         isLoadMore = loadMore;
177     }
178 
179     public Boolean getRefresh() {
180         return isRefresh;
181     }
182 
183     //设置是否支持下拉刷新
184     public void setRefreshEnable(Boolean refresh) {
185         isRefresh = refresh;
186     }
187 }

 

二、实际用例

已经定义好了RecyclerView,下面在Demo中实际使用和处理。

1、定义布局

布局文件很简单,就是一个RecyclerView

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout
 3     xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:id="@+id/activity_main"
 6     android:layout_width="match_parent"
 7     android:layout_height="match_parent"
 8     android:orientation="vertical"
 9     tools:context="com.liuting.refreshloadmorelistview.MainActivity">
10 
11     <com.liuting.library.RefreshLoadMoreRecycleView
12         android:id="@+id/main_recycle_view_data"
13         android:layout_width="match_parent"
14         android:layout_height="match_parent"
15         android:scrollbars="none"
16          />
17 </LinearLayout>

2、定义RecyclerView.Adapter

RecyclerView.Adapter在这里就简单处理了,列表布局直接使用Android自带的。

 1 import android.content.Context;
 2 import android.support.v7.widget.RecyclerView;
 3 import android.view.LayoutInflater;
 4 import android.view.View;
 5 import android.view.ViewGroup;
 6 import android.widget.TextView;
 7 
 8 import java.util.List;
 9 
10 /**
11  * Package:com.liuting.refreshloadmorelistview.adapter
12  * author:liuting
13  * Date:2017/2/16
14  * Desc:列表Adapter
15  */
16 
17 public class RefreshLoadMoreRecycleAdapter extends RecyclerView.Adapter<RefreshLoadMoreRecycleAdapter.ViewHolder> {
18     private List<String> list;
19     private Context context;
20 
21     public RefreshLoadMoreRecycleAdapter(Context context,List<String> list) {
22         this.context =context;
23         this.list = list;
24     }
25 
26     @Override
27     public RefreshLoadMoreRecycleAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
28         View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_expandable_list_item_1, parent, false);
29         RefreshLoadMoreRecycleAdapter.ViewHolder viewHolder = new RefreshLoadMoreRecycleAdapter.ViewHolder(view);
30         return viewHolder;
31     }
32 
33     @Override
34     public void onBindViewHolder(ViewHolder holder, int position) {
35         holder.text.setText(list.get(position));
36         holder.itemView.setTag(position);
37     }
38 
39     @Override
40     public int getItemCount() {
41         return list.size();
42     }
43 
44     class ViewHolder extends RecyclerView.ViewHolder{
45         private TextView text;
46 
47         public ViewHolder(View itemView) {
48             super(itemView);
49             text=(TextView)itemView.findViewById(android.R.id.text1);
50         }
51     }
52 }

3、在Activity中定义好控件以及数据加载操作

实现自定义RecyclerView中的数据加载事件监听,刷新、加载更多以及加载完成。

  1 import android.app.ProgressDialog;
  2 import android.os.Bundle;
  3 import android.os.Handler;
  4 import android.os.Message;
  5 import android.support.v7.app.AppCompatActivity;
  6 import android.support.v7.widget.LinearLayoutManager;
  7 import android.widget.Toast;
  8 
  9 import com.liuting.library.RefreshLoadMoreRecycleView;
 10 import com.liuting.refreshloadmorelistview.adapter.RefreshLoadMoreRecycleAdapter;
 11 
 12 import java.util.ArrayList;
 13 import java.util.List;
 14 
 15 public class MainActivity extends AppCompatActivity implements RefreshLoadMoreRecycleView.IOnScrollListener{
 16     private RefreshLoadMoreRecycleView recycleView;//下拉刷新RecycleView
 17     private List<String> list;//列表
 18     private RefreshLoadMoreRecycleAdapter adapter;//Adapter
 19     private ProgressDialog dialog;//提示框
 20     private static final int REFRESH_Load=0;//下拉刷新
 21     private static final int MORE_Load=1;//加载更多
 22     private Handler handler =new Handler(){
 23         @Override
 24         public void handleMessage(Message msg) {
 25             super.handleMessage(msg);
 26             switch (msg.what){
 27                 case REFRESH_Load:
 28                     recycleView.setLoadMoreEnable(true);
 29                     dismissDialog();
 30                     if(list!=null){
 31                         list.clear();
 32                     }
 33                     loadData();
 34                     adapter.notifyDataSetChanged();
 35                     break;
 36                 case MORE_Load:
 37                     recycleView.setLoadMoreEnable(false);
 38                     dismissDialog();
 39                     loadData();
 40                     adapter.notifyDataSetChanged();
 41                     break;
 42             }
 43         }
 44     };
 45 
 46     @Override
 47     protected void onCreate(Bundle savedInstanceState) {
 48         super.onCreate(savedInstanceState);
 49         setContentView(R.layout.activity_main);
 50         initView();
 51     }
 52 
 53     public void initView(){
 54         dialog = new ProgressDialog(MainActivity.this);
 55 
 56         list=new ArrayList<>();
 57         loadData();
 58         recycleView = (RefreshLoadMoreRecycleView)findViewById(R.id.main_recycle_view_data);
 59 
 60         final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(MainActivity.this);
 61         recycleView.setLayoutManager(linearLayoutManager);
 63         adapter = new RefreshLoadMoreRecycleAdapter(MainActivity.this,list);
 64         recycleView.setAdapter(adapter);
 65         recycleView.setListener(this);
 66         recycleView.setRefreshEnable(true);
 67         recycleView.setLoadMoreEnable(true);
 68     }
 69 
 70     /**
 71      * 加载数据
 72      */
 73     public void loadData(){
 74         for(int i=0;i<10;i++ ){
 75             list.add("It is "+i);
 76         }
 77     }
 78 
 79     @Override
 80     public void onRefresh() {
 81         showDialog();
 82         new Thread(){
 83             @Override
 84             public void run() {
 85                 super.run();
 86                 try {
 87                     sleep(5000);
 88                     handler.sendEmptyMessage(REFRESH_Load);
 89                 } catch (InterruptedException e) {
 90                     e.printStackTrace();
 91                 }
 92             }
 93         }.start();
 94     }
 95 
 96     @Override
 97     public void onLoadMore() {
 98         showDialog();
 99         new Thread(){
100             @Override
101             public void run() {
102                 super.run();
103                 try {
104                     sleep(5000);
105                     handler.sendEmptyMessage(MORE_Load);
106                 } catch (InterruptedException e) {
107                     e.printStackTrace();
108                 }
109             }
110         }.start();
111     }
112 
113     @Override
114     public void onLoaded() {
115         Toast.makeText(MainActivity.this,"Loaded all",Toast.LENGTH_SHORT).show();
116     }
117 
118     /**
119      * dismiss dialog
120      */
121     private void dismissDialog(){
122         if (dialog!=null&&dialog.isShowing()){
123             dialog.dismiss();
124         }
125     }
126 
127     /**
128      * show dialog
129      */
130     private void showDialog(){
131         if (dialog!=null&&!dialog.isShowing()){
132             dialog.show();
133         }
134     }
135 }

 

三、最终效果图

 

 

到这里就轻松实现了RecyclerView的下拉刷新和加载更多了。

源代码放在了Github上:https://github.com/LT5505/RefreshLoadMoreRecycleView

posted @ 2017-02-17 14:12  LT5505  阅读(1691)  评论(2编辑  收藏  举报