前言:利用SwipeRefreshLayout和RecyclerView来实现下拉刷新和加载更多,有很多的例子,但普遍都存在一个问题,当总的数据不够一屏时,FooterView也显示了,如果直接隐藏FooterView,加载更多时FooterView又不显示了,捣鼓了一阵子后,总算完美的解决了,所以记录一下,同时为了方便使用,进行了一些简单的封装。
直接进入主题,关于SwipeRefreshLayout和RecyclerView的一些基本介绍,就不在这里累述,不了解的童鞋,上网查一下吧!
一、封装自己的RefreshLayout控件
为什么要封装?为了使用方便;更为了Activity简单(MVP模式);因为Adapter的数据源类型不确定,所以采用泛型来实现。
java类和xml布局如下图
仔细的童鞋,已经发现了java类继承的是LinearLayout(xml根节点),为什么不用直接继承SwipeRefreshLayout(xml根节点)呢?其实一开始也是直接已SwipeRefreshLayout为根节点的,直接以SwipeRefreshLayout为根节点,运行后发现下拉刷新的颜色无法修改(swipeRefreshLayout.setColorSchemeColors(int color)无效),而且SwipeRefreshLayout.setRefreshing(false)方法也无效,导致无法释放下拉刷新,界面卡住。
要实现下拉刷新和加载更多,需要SwipeRefreshLayout监听OnRefreshListener和RecyclerView监听OnScrollListener,下拉刷新比较简单,如图
难点在于RecyclerView监听OnScrollListener,重写onScrollStateChanged和onScrolled方法,方法具体实现如下图
代码简单,逻辑也不复杂,图一主要实现“加载更多”,根据判断RecyclerView是否滑倒底部了;图二主要实现“不足一屏数据”的显示逻辑,数据少于一屏时,修改状态值为“初始化”,当状态为“到底”时,不进行操作,一共设计了4个状态(1-初始状态,全隐藏;2-正在加载,3-加载完成,4-加载到底,指没有更多数据了),后文具体交代;
因为把Adapter也封装到了RefreshLayout中,所以需要对外提供刷新和加载更多的方法,如图
到此处RefreshLayout.java就差不结束了,自定义控件相对来说还是比较简单;
二、封装Adapter(实现FooterView)
Adapter部分,其实主要就是给RecyclerView添加一个FooterView,首先定义一个泛型的BaseAbsAdapter抽象类(比较简单,也是为了项目方便使用),代码如下
public abstract class BaseAbsAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { protected List<T> mList; protected Context mContext; public BaseAbsAdapter(Context context) { mContext = context; mList = new ArrayList<>(); } /** * 下拉刷新 * @param list 列表 */ public abstract void onRefresh(List<T> list); /** * 加载更多 * @param list 列表 */ public abstract void onLoadMore(List<T> list); /** * 创建View * @param parent 父View * @param layout XML布局 * @return View */ protected View inflate(ViewGroup parent, int layout) { return LayoutInflater.from(mContext).inflate(layout, parent, false); } }
然后封装实现FooterView的WrapperAdapter类(这里何网络上的大部分实现功能都差不多,就不多累述,这里出现了上面说的4中状态,目前实现比较简单,就是对FooterView的操作,直接上代码)
class WrapperAdapter<T> extends BaseAbsAdapter<T> { private BaseAbsAdapter<T> mAdapter;// 适配器