RecyclerView 下拉刷新上拉加载
步骤:
- 首先直接定义一个XRecyclerView继承RecyclerView,重写他的三个构造方法。
 - init(Context mContext)方法用来初始化底部加载的view
 - 回到XRecyclerView,实现init
 - 判断是否滑动到底部,并且进行加载
 - 自定义一个adapter来把底部布局加进去。
 - 重写Adapter,通过状态判断是否显示“正在加载”
 - 定义一个mDataObserver
 
1. 首先直接定义一个XRecyclerView继承RecyclerView,重写他的三个构造方法。
public XRecylcerView(Context context) {
    this(context, null);
}
public XRecylcerView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
}
public XRecylcerView(Context context, AttributeSet attrs, int defStyle){
    super(context, attrs, defStyle);
    init(context);
}
2. init(Context mContext)方法用来初始化底部加载的view
先自定义一个底部布局LoadingMoreFooter继承Linearlayout,里面是一个居中显示的ProgressBar和一个TextView,添加一个方法setState(int state),来判定当前刷新的状态
public void setState(int state) {
        switch (state) {
            // 刷新中
      case STATE_LAODING:                
          progressCon.setVisibility(View.VISIBLE);
          mText.setText("正在刷新");
          this.setVisibility(View.VISIBLE);
            break;
      // 刷新完成
      case STATE_COMPLETE:
          mText.setText("刷新完成");
          this.setVisibility(View.GONE);
        break;            
      // 没有更多数据
      case STATE_NOMORE:
          mText.setText("没有更多数据啦");
                progressCon.setVisibility(View.GONE);
                this.setVisibility(View.VISIBLE);
              break;
     }
 }
3. 回到XRecyclerView,实现init
  private void init(Context context) {
        mContext = context;
        // loadingMoreEnabled为下拉的开关
        if (loadingMoreEnabled) {
            LoadingMoreFooter footerView = new LoadingMoreFooter(mContext);
            addFootView(footerView);
            mFootViews.get(0).setVisibility(GONE);
        }
    }
RecyclerView的上拉加载,原理很简单,无非就是当滑动到底部的时候,如果有数据,并且允许加载,就请求数据添加到adapter,而RecyclerView需要做的就是当加载的时候,在底部显示正在加载来提醒用户。
4.判断是否滑动到底部,并且进行加载
/**
* 监听滑动,来定位当前滑动到哪个地方
*
* @param state
*/
@Override
public void onScrollStateChanged(int state) {
super.onScrollStateChanged(state);
if (state == RecyclerView.SCROLL_STATE_IDLE
&& mLoadingListener != null && !isLoadingData && loadingMoreEnabled) {
LayoutManager layoutManager = getLayoutManager();
int lastVisibleItemPosition;
if (layoutManager instanceof GridLayoutManager) {
lastVisibleItemPosition =
((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
int[] into =
new int[((StaggeredGridLayoutManager) layoutManager).getSpanCount()];
((StaggeredGridLayoutManager) layoutManager).findLastVisibleItemPositions(into);
lastVisibleItemPosition = findMax(into);
} else {
lastVisibleItemPosition =
((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
}
if (layoutManager.getChildCount() > 0
&& lastVisibleItemPosition >= layoutManager.getItemCount() - 1
&& layoutManager.getItemCount() > layoutManager.getChildCount()
&& !isnomore) {
View footView = mFootViews.get(0);
isLoadingData = true;
if (footView instanceof LoadingMoreFooter) {
((LoadingMoreFooter) footView).setState(
LoadingMoreFooter.STATE_LAODING);
} else {
footView.setVisibility(View.VISIBLE);
}
mLoadingListener.onLoadMore();
// 一个回调接口,用来加载数据
}
}
}
写到这个地方,基本的上拉加载的逻辑就搞定了,然后就是处理细节。我们需要把底部布局LoadingMoreFooter加载到RecyclerView,这时候重写setAdapter(Adapter adapter)方法来添加一个adapter。
5. 自定义一个adapter来把底部布局加进去。自定义的Adapter如下:
   private class WrapAdapter extends RecyclerView.Adapter<ViewHolder> {
     private RecyclerView.Adapter adapter;
     private ArrayList<View> mFootViews;
     private int headerPosition = 0;
     public WrapAdapter(ArrayList<View> footViews, RecyclerView.Adapter adapter) {
         this.adapter = adapter;
         this.mFootViews = footViews;
     }
     @Override
     public void onAttachedToRecyclerView(RecyclerView recyclerView) {
         super.onAttachedToRecyclerView(recyclerView);
         RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
         if (manager instanceof GridLayoutManager) {
             final GridLayoutManager gridManager = ((GridLayoutManager) manager);
             gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                 @Override
                 public int getSpanSize(int position) {
                     return (isFooter(position)) ? gridManager.getSpanCount() : 1;
                 }
             });
         }
     }
     @Override
     public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
         super.onViewAttachedToWindow(holder);
         ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
         if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams && (isFooter(holder.getLayoutPosition()))
         {
             StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
             p.setFullSpan(true);
         }
     }
     public boolean isFooter(int position) {
         return position < getItemCount() && position >= getItemCount() - mFootViews.size();
     }
     public int getFootersCount() {
         return mFootViews.size();
     }
     @Override
     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         if (viewType == TYPE_FOOTER) {
             return new SimpleViewHolder(mFootViews.get(0));
         }
         return adapter.onCreateViewHolder(parent, viewType);
     }
     @Override
     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
         if (isHeader(position)) {
             return;
         }
         int adjPosition = position;
         int adapterCount;
         if (adapter != null) {
             adapterCount = adapter.getItemCount();
             if (adjPosition < adapterCount) {
                 adapter.onBindViewHolder(holder, adjPosition);
                 return;
             }
         }
     }
     @Override
     public int getItemCount() {
         if (adapter != null) {
             return getFootersCount() + adapter.getItemCount();
         } else {
             return getFootersCount();
         }
     }
     @Override
     public int getItemViewType(int position) {
         if (isFooter(position)) {
             return TYPE_FOOTER;
         }
         int adjPosition = position;
         int adapterCount;
         if (adapter != null) {
             adapterCount = adapter.getItemCount();
             if (adjPosition < adapterCount) {
                 return adapter.getItemViewType(adjPosition);
             }
         }
         return TYPE_NORMAL;
     }
     @Override
     public long getItemId(int position) {
         if (adapter != null) {
             int adjPosition = position - getHeadersCount();
             int adapterCount = adapter.getItemCount();
             if (adjPosition < adapterCount) {
                 return adapter.getItemId(adjPosition);
             }
         }
         return -1;
     }
     private class SimpleViewHolder extends RecyclerView.ViewHolder {
         public SimpleViewHolder(View itemView) {
             super(itemView);
         }
     }
 }
就是一个继承自RecyclerView.Adapter的adapter,主要用于根据类型加载不同的布局,普通的itemView和“正在加载”的底部提示。 定义一个mDataObserver
6. 回到setAdapter(Adapter adapter)方法
/**
* 重写Adapter,通过状态判断是否显示“正在加载”
*
* @param adapter
*/
@Override
public void setAdapter(Adapter adapter) {
this.mAdapter = adapter;
this.mWrapAdapter = new WrapAdapter(mFootViews, mAdapter);// 定义WrapAdapter
super.setAdapter(mWrapAdapter);// 通过父类方法将自定义的Adapter重新设置进去
mAdapter.registerAdapterDataObserver(mDataObserver);//请看下面分析
}
查看super.setAdapter()方法,会找到adapter.registerAdapterDataObserver(mObserver)方法,当adapter里面的数据发生改变时会即时监听并且更新。
那为什么还要把mAdapter再设置一遍呢?其实当我们调用通过我们自定义的RecyclerView来调用setAdapter方法时,只有当WrapAdapter数据改变的时候,才会有更新,而当我们仅仅只更新mAdapter里面的数据的时候,如果不监听,我们看到的itemView并没有改变。
7.定义一个mDataObserver
private final RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
        @Override
        public void onChanged() {
            mWrapAdapter.notifyDataSetChanged();
        }
        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount);
        }
        @Override
        public void onItemRangeChanged(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount);
        }
        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload);
        }
        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount);
        }
        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
        }
    };
都是直接调用父类的方法就可以。
这样一个RecyclerView的上拉加载逻辑就全部搞定了,这是极其简单的封装方法,所以逻辑没有多么的复杂。
好的,来回顾一下逻辑:重写RecyclerView进行滑动监听,当滑动到底部的时候通过重写setAdapter来将底部视图加载出来,最后对mAdapter进行数据更改的监听。
上拉刷新的逻辑更简单,因为有谷歌的SwipeRefreshLayout,所以实现起来就简单很多,首先来看布局文件
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swipe"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<com.baiyyyhjl.pullrecyclerview.recyclerview.XRecylcerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.v4.widget.SwipeRefreshLayout>
直接用SwipeRefreshLayout将我们刚才自定义的RecyclerView包裹起来,然后swipeRefreshLayout.setOnRefreshListener(this)进行监听,实现onRefresh()接口来实现加载的逻辑。
就这样,一个简单实用的RecyclerView上拉加载,下拉刷新就实现了。没有多余的布局文件,极其简便。
当我们项目中有多个RecyclerView并且要求上拉加载,下拉刷新的时候,我们可以定义一个抽象类,只通过修改itemView的布局就能实现。
RecyclerView 下拉刷新上拉加载的更多相关文章
- Android 下拉刷新上啦加载SmartRefreshLayout + RecyclerView
		
在弄android刷新的时候,可算是耗费了一番功夫,最后发觉有现成的控件,并且非常好用,这里记录一下. 原文是 https://blog.csdn.net/huangxin112/article/de ...
 - SwipeRefreshLayout实现下拉刷新上滑加载
		
1. 效果图 2.RefreshLayout.java package myapplication.com.myapplication; import android.content.Context; ...
 - 移动端下拉刷新上拉加载-mescroll.js插件
		
最近无意间看到有这么一个上拉刷新下拉加载的插件 -- mescroll.js,个人感觉挺好用的,官网地址是:http://www.mescroll.com 然后我就看了一下文档,简单的写了一个小dem ...
 - 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载
		
title: 带你实现开发者头条APP(五)--RecyclerView下拉刷新上拉加载 tags: -RecyclerView,下拉刷新,上拉加载更多 grammar_cjkRuby: true - ...
 - RecyclerView下拉刷新上拉加载(三)—对Adapter的封装
		
RecyclerView下拉刷新上拉加载(一) http://blog.csdn.net/baiyuliang2013/article/details/51506036 RecyclerView下拉刷 ...
 - RecyclerView下拉刷新上拉加载(二)
		
listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...
 - RecyclerView下拉刷新上拉加载(一)
		
listview下拉刷新上拉加载扩展(一) http://blog.csdn.net/baiyuliang2013/article/details/50252561 listview下拉刷新上拉加载扩 ...
 - MaterialRefreshLayout+ListView 下拉刷新 上拉加载
		
效果图是这样的,有入侵式的,非入侵式的,带波浪效果的......就那几个属性,都给出来了,自己去试就行. 下拉刷新 上拉加载 关于下拉刷新-上拉加载的效果,有许许多多的实现方式,百度了一下竟然有几十种 ...
 - 自定义ListView下拉刷新上拉加载更多
		
自定义ListView下拉刷新上拉加载更多 自定义RecyclerView下拉刷新上拉加载更多 Listview现在用的很少了,基本都是使用Recycleview,但是不得不说Listview具有划时 ...
 - ListView实现Item上下拖动交换位置  并且实现下拉刷新  上拉加载更多
		
ListView实现Item上下拖动交换位置 并且实现下拉刷新 上拉加载更多 package com.example.ListViewDragItem; import android.app.Ac ...
 
随机推荐
- hibernate不关闭session后果
			
(转自:百度知道) 看是怎么获得session的. 方法1: 通过配置监听器后,在Dao中用getCurrentSession获取(内部原理....),此时无需管理session的关闭与否: 方法2: ...
 - 【英语】Bingo口语笔记(31) - Bring系列
			
bring up 表示在哪长大 要用被动形式 BYOB 请自带酒瓶
 - 正确理解 AsyncTask,Looper,Handler三者之间的关系(基于android 4.0)
			
Looper 和Handler 是理解好AsyncTask的一个基础,我们可以先从这里开始,先给出一个主线程和子线程互相通信的例子. package com.example.loopertest; i ...
 - MongoDB配置客户端
			
新建mongodb27017.bat文件 内容为: mongo 127.0.0.1:27017/admin 连接成功! 来自为知笔记(Wiz)
 - 编译及load mydqli.so文件
			
(1)cd /usr/local/php-5.2.17/ext/mysqli(2)输入/usr/local/php/bin/phpize 回车(3)./configure --prefix=/usr/ ...
 - AE+C# 图层中增加相应属性标注
			
原文 AE+C# 图层中增加相应属性标注 ) { IGeoFeatureLayer pGeoFeatureLayer; ILineLabelPosition pLineLabelPosition; I ...
 - J2EE事务
			
一.J2EE 事务处理方式 1. 本地事务:紧密依赖于底层资源管理器(例如数据库连接 ),事务处理局限在当前事务资源内.此种事务处理方式不存在对应用服务器的依赖,因而部署灵活却无法支持多数据源的分布式 ...
 - MYSQL性能查看(命中率,慢查询)
			
网上有很多的文章教怎么配置MySQL服务器,但考虑到服务器硬件配置的不同,具体应用的差别,那些文章的做法只能作为初步设置参考,我们需要根据自己的情况进行配置优化,好的做法是MySQL服务器稳定运行了一 ...
 - Java读取excel指定sheet中的各行数据,存入二维数组,包括首行,并打印
			
1. 读取 //读取excel指定sheet中的各行数据,存入二维数组,包括首行 public static String[][] getSheetData(XSSFSheet sheet) thro ...
 - 虚幻4以及DX12将允许开发者利用Xbox One的更多性能(转)
			
GamingBolt 最近采访了 Epic Games 的总经理 Ray Davis,讨论了有关旗下虚幻引擎(Unreal Engine)的议题.在这次的访谈中,Ray 解释了关于使用 DirectX ...