RecyclerView 下拉刷新上拉加载更多

来源:互联网 发布:部队网络安全管理 编辑:程序博客网 时间:2024/05/22 06:46

这几天研究了下RecyclerView的使用和封装,发现还是蛮好用的,现在把学习成果分享给大家,主要是关于上拉加载更多的封装,之所以没有封装下拉刷新也是因为SwipeRefreshLayout的存在,并且它更加符合MD风格.

注意该封装只适用于类似listview这种列表形式的

附上效果



先来看看activity中使用该控件的代码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.byzk.www.recyclerviewpackage;  
  2.   
  3. import android.os.Bundle;  
  4. import android.os.Handler;  
  5. import android.support.v4.widget.SwipeRefreshLayout;  
  6. import android.support.v7.app.AppCompatActivity;  
  7. import android.support.v7.widget.LinearLayoutManager;  
  8.   
  9. import java.util.ArrayList;  
  10. import java.util.List;  
  11.   
  12. public class MainActivity extends AppCompatActivity {  
  13.   
  14.     private List<String> dataList = new ArrayList<>();  
  15.     private RefreshRecyclerView rv;  
  16.     private MyAdapter myAdapter;  
  17.     private SwipeRefreshLayout srl;  
  18.   
  19.     @Override  
  20.     protected void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.activity_main);  
  23.   
  24.         initView();  
  25.         initData();  
  26.         initListener();  
  27.     }  
  28.   
  29.     private void initView() {  
  30.         srl = (SwipeRefreshLayout) findViewById(R.id.srl);  
  31.         srl.setColorSchemeResources(android.R.color.holo_red_light, android.R.color.holo_blue_light, android.R.color.holo_green_light);  
  32.         rv = (RefreshRecyclerView) findViewById(R.id.rv);  
  33.         rv.setLayoutManager(new LinearLayoutManager(this));  
  34.         rv.setLoadMoreEnable(true);//允许加载更多  
  35.         rv.setFooterResource(R.layout.item_footer);//设置脚布局  
  36.         myAdapter = new MyAdapter(dataList);  
  37.         rv.setAdapter(myAdapter);  
  38.     }  
  39.   
  40.     private void initData() {  
  41.         for (int i = 0; i < 20; i++) {  
  42.             dataList.add("数据" + i);  
  43.         }  
  44.         rv.notifyData();  
  45.     }  
  46.   
  47.     private void initListener() {  
  48.         rv.setOnLoadMoreListener(new RefreshRecyclerView.OnLoadMoreListener() {  
  49.             @Override  
  50.             public void loadMoreListener() {  
  51.                 handler.postDelayed(new Runnable() {  
  52.                     @Override  
  53.                     public void run() {  
  54.                         for (int i = 0; i < 10; i++) {  
  55.                             dataList.add("更多数据" + i);  
  56.                         }  
  57.                         rv.notifyData();//刷新数据  
  58.                     }  
  59.                 }, 2000);  
  60.             }  
  61.         });  
  62.         srl.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {  
  63.             @Override  
  64.             public void onRefresh() {  
  65.                 handler.postDelayed(new Runnable() {  
  66.                     @Override  
  67.                     public void run() {  
  68.                         srl.setRefreshing(false);  
  69.                         dataList.add(0"最新数据");  
  70.                         rv.notifyData();//刷新数据  
  71.                     }  
  72.                 }, 2000);  
  73.             }  
  74.         });  
  75.     }  
  76.   
  77.   
  78.     private Handler handler = new Handler();  
  79.   
  80.   
  81. }  
可以发现activity中,recyclerview的写法没有太大变化,只是有如下几点需要注意

1.如果想要加载更多需要调用(必须)

rv.setLoadMoreEnable(true)

2.如果希望加载更多时候有脚布局提示需要调用(不是必须的)

rv.setFooterResource(int res)

3.实现加载更多回调(必须)

rv.setOnLoadMoreListener()

4.刷新数据调用(必须)

rv.notifyData()


activity布局代码

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:tools="http://schemas.android.com/tools"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     tools:context="com.byzk.www.recyclerviewpackage.MainActivity">  
  7.     <android.support.v4.widget.SwipeRefreshLayout  
  8.         android:id="@+id/srl"  
  9.         android:layout_width="wrap_content"  
  10.         android:layout_height="wrap_content">  
  11.         <com.byzk.www.recyclerviewpackage.RefreshRecyclerView  
  12.             android:id="@+id/rv"  
  13.             android:layout_width="match_parent"  
  14.             android:layout_height="wrap_content" />  
  15.     </android.support.v4.widget.SwipeRefreshLayout>  
  16.   
  17.   
  18. </RelativeLayout>  

下拉刷新用的是v4包中的SwipeRefreshLayout直接包裹在自己封装的RecyclerView的外层,上拉加载更多用的是自己封装的RecyclerView.


前方高能,接下来有一大波代码来袭,核心代码RecyclerView的封装如下

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.byzk.www.recyclerviewpackage;  
  2.   
  3. import android.content.Context;  
  4. import android.support.v7.widget.LinearLayoutManager;  
  5. import android.support.v7.widget.RecyclerView;  
  6. import android.util.AttributeSet;  
  7. import android.util.Log;  
  8. import android.view.LayoutInflater;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12.   
  13. import jp.wasabeef.recyclerview.animators.adapters.SlideInBottomAnimationAdapter;  
  14.   
  15. /** 
  16.  * Author: zhuliyuan 
  17.  * Time: 下午 3:26 
  18.  * 将脚布局放在最后一个条目,当加载更多的时候显示,加载完成的时候隐藏 
  19.  * 
  20.  */  
  21.   
  22. public class RefreshRecyclerView extends RecyclerView {  
  23.   
  24.     private AutoLoadAdapter autoLoadAdapter;  
  25.   
  26.     public RefreshRecyclerView(Context context) {  
  27.         this(context, null);  
  28.     }  
  29.   
  30.     public RefreshRecyclerView(Context context, AttributeSet attrs) {  
  31.         this(context, attrs, 0);  
  32.     }  
  33.   
  34.     public RefreshRecyclerView(Context context, AttributeSet attrs, int defStyle) {  
  35.         super(context, attrs, defStyle);  
  36.         init();  
  37.     }  
  38.   
  39.     private boolean isLoadingMore = false;//是否正在加载更多  
  40.     private OnLoadMoreListener loadMoreListener;//加载数据监听  
  41.     private boolean loadMoreEnable = false;//是否允许加载更多  
  42.     private int footerResource = -1;//脚布局  
  43.     private boolean footer_visible = false;//脚部是否可以见  
  44.     private void init() {  
  45.         setOnScrollListener(new OnScrollListener() {  
  46.             @Override  
  47.             public void onScrollStateChanged(RecyclerView recyclerView, int newState) {  
  48.                 super.onScrollStateChanged(recyclerView, newState);  
  49.   
  50.                 if (getAdapter() != null && getLayoutManager() != null) {  
  51.                     int lastVisiblePosition = ((LinearLayoutManager) getLayoutManager()).findLastVisibleItemPosition();  
  52.                     int itemCount = getAdapter().getItemCount();  
  53.                     /** 
  54.                      * 控制下拉刷新回调 
  55.                      * itemCount != 0 排除没有数据情况 
  56.                      * lastVisiblePosition + 4 >= itemCount - 1 最后可见+4 >= 总条数 加载更多 
  57.                      * distanceY < 0 为上拉的时候才刷新 
  58.                      */  
  59.                     if (distanceY < 0 && itemCount != 0 && lastVisiblePosition + 4 >= itemCount - 1 && !isLoadingMore && loadMoreEnable) {  
  60.                         Log.i("test","加载更多");  
  61.                         //正在加载更多  
  62.                         loading();  
  63.                         if (footerResource != -1){//有脚布局  
  64.                             //显示脚布局  
  65.                             footer_visible = true;  
  66.                             getAdapter().notifyItemChanged(itemCount - 1);  
  67.                         }  
  68.                         if (loadMoreListener != null) {  
  69.                             loadMoreListener.loadMoreListener();  
  70.                         }  
  71.                     }  
  72.                 }  
  73.             }  
  74.         });  
  75.     }  
  76.   
  77.     /** 
  78.      * 判断滑动方向 
  79.      */  
  80.     private float distanceY = 0;  
  81.     float startY = 0;  
  82.     @Override  
  83.     public boolean dispatchTouchEvent(MotionEvent ev) {  
  84.         float y = ev.getRawY();  
  85.         switch (ev.getAction()){  
  86.             case MotionEvent.ACTION_DOWN:  
  87.                 startY = y;  
  88.                 break;  
  89.             case MotionEvent.ACTION_MOVE:  
  90.                 distanceY = y - startY;  
  91.                 startY = y;  
  92.                 break;  
  93.         }  
  94.         return super.dispatchTouchEvent(ev);  
  95.     }  
  96.   
  97.     @Override  
  98.     public void setAdapter(Adapter adapter) {  
  99.         SlideInBottomAnimationAdapter slideInBottomAnimationAdapter = new SlideInBottomAnimationAdapter(adapter);  
  100.         slideInBottomAnimationAdapter.setDuration(600);  
  101.         autoLoadAdapter = new AutoLoadAdapter(slideInBottomAnimationAdapter);//添加动画  
  102.         super.setAdapter(autoLoadAdapter);  
  103.     }  
  104.   
  105.     /** 
  106.      * 设置是否允许加载更多 
  107.      * 
  108.      * @param isEnable 
  109.      */  
  110.     public void setLoadMoreEnable(boolean isEnable) {  
  111.         this.loadMoreEnable = isEnable;  
  112.     }  
  113.   
  114.     /** 
  115.      * 设置脚布局 
  116.      */  
  117.     public void setFooterResource(int footerResource) {  
  118.         this.footerResource = footerResource;  
  119.     }  
  120.   
  121.   
  122.     /** 
  123.      * 加载完成 
  124.      */  
  125.     private void loadMoreComplete() {  
  126.         this.isLoadingMore = false;  
  127.     }  
  128.   
  129.     /** 
  130.      * 正在刷新 
  131.      */  
  132.     private void loading(){  
  133.         this.isLoadingMore = true;//设置正在刷新  
  134.     }  
  135.   
  136.     /** 
  137.      * 加载更多数据回调 
  138.      * 
  139.      * @param listener 
  140.      */  
  141.     public void setOnLoadMoreListener(OnLoadMoreListener listener) {  
  142.         this.loadMoreListener = listener;  
  143.     }  
  144.   
  145.     public interface OnLoadMoreListener {  
  146.         void loadMoreListener();//上拉刷新  
  147.     }  
  148.   
  149.   
  150.     /** 
  151.      * 刷新数据 
  152.      */  
  153.     public void notifyData() {  
  154.         if (getAdapter() != null) {  
  155.             loadMoreComplete();  
  156.             if(footerResource != -1 && loadMoreEnable){  
  157.                 //隐藏脚布局  
  158.                 footer_visible = false;  
  159.             }  
  160.             getAdapter().notifyDataSetChanged();  
  161.   
  162.         }  
  163.     }  
  164.   
  165.     public class AutoLoadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {  
  166.         private Adapter dataAdapter;//数据adapter  
  167.         private final int TYPE_FOOTER = Integer.MAX_VALUE;//底部布局  
  168.   
  169.         public AutoLoadAdapter(RecyclerView.Adapter adapter) {  
  170.             this.dataAdapter = adapter;  
  171.         }  
  172.   
  173.         @Override  
  174.         public int getItemViewType(int position) {  
  175.             if (position == getItemCount() - 1 && loadMoreEnable && footerResource != -1 && footer_visible) {  
  176.                 return TYPE_FOOTER;  
  177.             }  
  178.             if (dataAdapter.getItemViewType(position) == TYPE_FOOTER) {  
  179.                 throw new RuntimeException("adapter中itemType不能为:" + Integer.MAX_VALUE);  
  180.             }  
  181.             return dataAdapter.getItemViewType(position);  
  182.   
  183.         }  
  184.   
  185.         @Override  
  186.         public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  187.             ViewHolder holder = null;  
  188.             if (viewType == TYPE_FOOTER) {//脚部  
  189.                 holder = new FooterViewHolder(LayoutInflater.from(getContext()).inflate(footerResource, parent, false));  
  190.             } else {//数据  
  191.                 holder = dataAdapter.onCreateViewHolder(parent, viewType);  
  192.             }  
  193.             return holder;  
  194.         }  
  195.   
  196.         @Override  
  197.         public void onBindViewHolder(ViewHolder holder, int position) {  
  198.             int itemViewType = getItemViewType(position);  
  199.             if (itemViewType != TYPE_FOOTER) {  
  200.                 dataAdapter.onBindViewHolder(holder, position);  
  201.             }  
  202.         }  
  203.   
  204.         @Override  
  205.         public int getItemCount() {  
  206.             if (dataAdapter.getItemCount() != 0) {  
  207.                 int count = dataAdapter.getItemCount();  
  208.                 if (loadMoreEnable && footerResource != -1 && footer_visible) {  
  209.                     count++;  
  210.                 }  
  211.                 return count;  
  212.             }  
  213.             return 0;  
  214.         }  
  215.   
  216.         public class FooterViewHolder extends RecyclerView.ViewHolder {  
  217.   
  218.             public FooterViewHolder(View itemView) {  
  219.                 super(itemView);  
  220.             }  
  221.         }  
  222.   
  223.     }  
  224.   
  225. }  


这里封装了上拉加载更多,自己写了个adpter壳子,当允许上拉加载更多并且设置了脚布局的时候将脚布局加载到最后一个条目,根据最后可见条目位置与总条数的比较来回调加载更多刷新,其他时候数据都来源于自己写的DataAdapter,下拉刷新可以按同样原理实现为了MD设计风格,这里我就直接套的SwipeRefreshLayout了.


提供数据Adapter如下

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. package com.byzk.www.recyclerviewpackage;  
  2.   
  3. import android.support.v7.widget.RecyclerView;  
  4. import android.view.LayoutInflater;  
  5. import android.view.View;  
  6. import android.view.ViewGroup;  
  7. import android.widget.TextView;  
  8.   
  9. import java.util.List;  
  10.   
  11. /** 
  12.  * Author: zhuliyuan 
  13.  * Time: 下午 5:36 
  14.  */  
  15.   
  16. public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {  
  17.   
  18.   
  19.     private List<String> dataList;  
  20.   
  21.     public MyAdapter(List<String> dataList) {  
  22.         this.dataList = dataList;  
  23.     }  
  24.   
  25.     @Override  
  26.     public MyAdapter.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {  
  27.         MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_layout, parent, false));  
  28.         return myViewHolder;  
  29.     }  
  30.   
  31.     @Override  
  32.     public void onBindViewHolder(MyAdapter.MyViewHolder holder, int position) {  
  33.         holder.tv.setText(dataList.get(position));  
  34.     }  
  35.   
  36.     public class MyViewHolder extends RecyclerView.ViewHolder{  
  37.   
  38.         private TextView tv;  
  39.   
  40.         public MyViewHolder(View itemView) {  
  41.             super(itemView);  
  42.             tv = (TextView) itemView.findViewById(R.id.tv);  
  43.         }  
  44.     }  
  45.   
  46.     @Override  
  47.     public int getItemCount() {  
  48.         return (dataList == null || dataList.size() == 0)?0:dataList.size();  
  49.     }  
  50.   
  51. }  

item布局如下

[java] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     xmlns:card_view="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="80dp"  
  6.     android:layout_marginLeft="5dp"  
  7.     android:layout_marginRight="5dp"  
  8.     android:layout_marginTop="10dp"  
  9.     android:clickable="true"  
  10.     android:foreground="?attr/selectableItemBackground"  
  11.     card_view:cardBackgroundColor="#0094ff"  
  12.     card_view:cardCornerRadius="6dp"  
  13.     card_view:cardElevation="5dp">  
  14.   
  15.     <TextView  
  16.         android:id="@+id/tv"  
  17.         android:layout_width="wrap_content"  
  18.         android:layout_height="wrap_content"  
  19.         android:layout_gravity="center"  
  20.         android:text="哈哈哈"  
  21.         android:textColor="#fff" />  
  22. </android.support.v7.widget.CardView>  

提供数据adapter和item布局都是普通写法,这里不过多赘言



源码传送门

项目中recyclerview动画地址https://github.com/wasabeef/recyclerview-animators

到此封装完成,,如果有bug或者建议欢迎留言.



转自:http://blog.csdn.net/zly921112/article/details/50370494

1 0
原创粉丝点击