android.support.v7 包提供了一个新的组件:RecycleView,用以提供一个灵活的列表试图、显示大型数据集,它支持局部刷新、显示动画等功能,可以用来取代ListView与GridView.

  然而在使用的过程中却遇到一些问题,基本现在手机页面都会有滑动到底部加载更多的功能,而RecycleView 并没有提供像ListView的addFooter等方法,所以实现起来还是有点麻烦。经过一段时间的摸索,终于找到实现RecycleView加载更多的方法。

  本文主要通过RecycleView 的 ItemViewType 来实现RecycleView滑动到底部加载更多功能,支持 列表、网格、瀑布流等布局。

  根据ItemViewType创建两种布局,一个用于显示正常内容的布局,一个用于加载布局,然后监听RecycleView的滚动事件,当滑动到底部时添加加载布局,对于列表布局来说很简单,不再熬述,然而对于网格布局与瀑布流布局来说,要解决"加载布局只占用一列"的问题,

  1.对于网格布局,GridLayoutManager 提供了一个 setSpanSizeLookup() 的方法,用来设置每个条目可以占用的列数,默认为1.

  2.对于瀑布流,StaggeredGridLayoutManager 提供了一个 StaggeredGridLayoutManager.LayoutParams 内部静态类,此类中有一个setFullSpan() 方法,用来设置条目跨越全列。

  

  3.基类的实现方式如下:子类只需要重写以下方法:

    onCreateNormalViewHolder(ViewGroup parent);

    onBindNormalViewHolder(RecyclerView.ViewHolder holder, int position);

 /**
* Created by sunwei on 2015/12/4.
* Email: lx_sunwei@163.com.
* Description: recycleView 滑动到底部加载更多
*/
public abstract class BaseLoadingAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private static final String TAG = "BaseLoadingAdapter"; //是否正在加载
public boolean mIsLoading = false;
//正常条目
private static final int TYPE_NORMAL_ITEM = 0;
//加载条目
private static final int TYPE_LOADING_ITEM = 1;
//加载viewHolder
private LoadingViewHolder mLoadingViewHolder;
//瀑布流
private StaggeredGridLayoutManager mStaggeredGridLayoutManager;
//数据集
private CircularArray<T> mTs;
//首次进入
private boolean mFirstEnter = true;
private RecyclerView mRecyclerView; public BaseLoadingAdapter(RecyclerView recyclerView, CircularArray<T> ts) { mTs = ts; mRecyclerView = recyclerView; setSpanCount(recyclerView); //notifyLoading();
} private OnLoadingListener mOnLoadingListener; /**
* 加载更多接口
*/
public interface OnLoadingListener {
void loading();
} /**
* 设置监听接口
*
* @param onLoadingListener onLoadingListener
*/
public void setOnLoadingListener(OnLoadingListener onLoadingListener) {
setScrollListener(mRecyclerView);
mOnLoadingListener = onLoadingListener;
} /**
* 加载完成
*/
public void setLoadingComplete() {
if (mTs.size() > 0 && mTs.getLast() == null) {
mIsLoading = false;
mTs.removeFromEnd(1);
notifyItemRemoved(mTs.size() - 1);
}
} /**
* 没有更多数据
*/
public void setLoadingNoMore() {
mIsLoading = false;
if (mLoadingViewHolder != null) {
mLoadingViewHolder.progressBar.setVisibility(View.GONE);
mLoadingViewHolder.tvLoading.setText("已加载完!");
}
} /**
* 加载失败
*/
public void setLoadingError() {
if (mLoadingViewHolder != null) {
mIsLoading = false;
mLoadingViewHolder.progressBar.setVisibility(View.GONE);
mLoadingViewHolder.tvLoading.setText("加载失败,点击重新加载!"); mLoadingViewHolder.tvLoading.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mOnLoadingListener != null) {
mIsLoading = true;
mLoadingViewHolder.progressBar.setVisibility(View.VISIBLE);
mLoadingViewHolder.tvLoading.setText("正在加载..."); mOnLoadingListener.loading();
}
}
});
}
} /**
* @return Whether it is possible for the child view of this layout to
* scroll up. Override this if the child view is a custom view.
*/
private boolean canScrollDown(RecyclerView recyclerView) {
return ViewCompat.canScrollVertically(recyclerView, 1);
} /**
* 设置加载item占据一行
*
* @param recyclerView recycleView
*/
private void setSpanCount(RecyclerView recyclerView) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); if (layoutManager == null) {
Log.e(TAG, "LayoutManager 为空,请先设置 recycleView.setLayoutManager(...)");
} //网格布局
if (layoutManager instanceof GridLayoutManager) {
final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int type = getItemViewType(position);
if (type == TYPE_NORMAL_ITEM) {
return 1;
} else {
return gridLayoutManager.getSpanCount();
}
}
});
} //瀑布流布局
if (layoutManager instanceof StaggeredGridLayoutManager) {
mStaggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
}
} /**
* 显示加载
*/
private void notifyLoading() {
if (mTs.size() != 0 && mTs.getLast() != null) {
mTs.addLast(null);
notifyItemInserted(mTs.size() - 1);
}
} /**
* 监听滚动事件
*
* @param recyclerView recycleView
*/
private void setScrollListener(RecyclerView recyclerView) {
if(recyclerView == null) {
Log.e(TAG, "recycleView 为空");
return;
} recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
} @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy); if (!canScrollDown(recyclerView)) { //首次进入不加载
if (!mIsLoading && !mFirstEnter) { notifyLoading(); mIsLoading = true; if (mLoadingViewHolder != null) {
mLoadingViewHolder.progressBar.setVisibility(View.VISIBLE);
mLoadingViewHolder.tvLoading.setText("正在加载...");
} if (mOnLoadingListener != null) {
mOnLoadingListener.loading();
}
}
} if (mFirstEnter) {
mFirstEnter = false;
}
}
});
} /**
* 创建viewHolder
*
* @param parent viewGroup
* @return viewHolder
*/
public abstract RecyclerView.ViewHolder onCreateNormalViewHolder(ViewGroup parent); /**
* 绑定viewHolder
*
* @param holder viewHolder
* @param position position
*/
public abstract void onBindNormalViewHolder(RecyclerView.ViewHolder holder, int position); /**
* 加载布局
*/
private class LoadingViewHolder extends RecyclerView.ViewHolder {
public ProgressBar progressBar;
public TextView tvLoading;
public LinearLayout llyLoading; public LoadingViewHolder(View view) {
super(view); progressBar = (ProgressBar) view.findViewById(R.id.progress_loading);
tvLoading = (TextView) view.findViewById(R.id.tv_loading);
llyLoading = (LinearLayout) view.findViewById(R.id.lly_loading);
}
} @Override
public int getItemViewType(int position) {
T t = mTs.get(position);
if (t == null) {
return TYPE_LOADING_ITEM;
} else {
return TYPE_NORMAL_ITEM;
}
} @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_NORMAL_ITEM) {
return onCreateNormalViewHolder(parent);
} else {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.loading_layout, parent, false);
mLoadingViewHolder = new LoadingViewHolder(view);
return mLoadingViewHolder;
}
} @Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int type = getItemViewType(position);
if (type == TYPE_NORMAL_ITEM) {
onBindNormalViewHolder(holder, position);
} else { if (mStaggeredGridLayoutManager != null) {
StaggeredGridLayoutManager.LayoutParams layoutParams =
new StaggeredGridLayoutManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.setFullSpan(true); mLoadingViewHolder.llyLoading.setLayoutParams(layoutParams);
}
}
} @Override
public int getItemCount() {
return mTs.size();
}
}

Base Loading Adapter

4.一个简单的列子

 /**
* Created by sunwei on 2015/12/4.
* Email: lx_sunwei@163.com.
* Description: 滑动到底部加载更多
*/
public class DesignLoaderMoreAdapter extends BaseLoadingAdapter<DesignItem> { private CircularArray<DesignItem> mDesignItems; public DesignLoaderMoreAdapter(RecyclerView recyclerView, CircularArray<DesignItem> datas) {
super(recyclerView, datas); mDesignItems = datas;
} //正常条目
public class DesignViewHolder extends RecyclerView.ViewHolder {
public TextView textView;
public CardView cardView;
public DesignViewHolder(View view) {
super(view);
textView = (TextView) view.findViewById(R.id.tv_design);
cardView = (CardView) view.findViewById(R.id.cardView_designer); }
} @Override
public RecyclerView.ViewHolder onCreateNormalViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_item_design, parent, false);
return new DesignViewHolder(view);
} @Override
public void onBindNormalViewHolder(RecyclerView.ViewHolder holder, int position) {
DesignViewHolder viewHolder = (DesignViewHolder)holder;
DesignItem designItem = mDesignItems.get(position);
if (position == 10) {
//设置瀑布流的条目大小
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(260, 360);
lp.setMargins(10, 40, 10, 80);
viewHolder.cardView.setLayoutParams(lp);
} viewHolder.textView.setText(designItem.name);
}
}

Sample

      

项目地址:https://github.com/lxsunwei/MaterialDesign

RecycleView 滑动到底部,加载更多的更多相关文章

  1. 滚动到底部加载更多及下拉刷新listview的使用

    最新内容建议直接访问原文:滚动到底部加载更多及下拉刷新listview的使用 本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用. 该ListView优点包括:a. 可自定义下 ...

  2. XRecyclerView:实现下拉刷新、滚动到底部加载更多以及添加header功能的RecyclerView

    介绍: 一个实现了下拉刷新,滚动到底部加载更多以及添加header功能的的RecyclerView.使用方式和RecyclerView完全一致,不需要额外的layout,不需要写特殊的adater. ...

  3. ionic 上拉加载更多&瀑布流加载&滚动到底部加载更多 主意事项

    首先下拉刷新的代码是这样的,标红的地方为关键代码 <html> <head> <meta charset="utf-8"> <meta n ...

  4. jquery页面滑到底部加载更多

    $(window).scroll(function(){ var _scrolltop = $('body').scrollTop();if(_scrolltop+_winHeight>_doc ...

  5. Jquery实现滚动到底部加载更多(最原始)

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...

  6. vant list列表滚动到底部加载更多会滚动到顶部问题

    如果使用异步加载数据并使用了vant中的toast做加载中提示,则有可能会导致列表滚动高度为0,也就是回到了顶部.只要在list加载回调里不使用toast就可以避免这个问题.

  7. JQuery ajax 滚动底部加载更多

    <%@ Page Language="C#" %> <%@ Import Namespace="System.IO" %> <%@ ...

  8. RecyclerView实例-实现可下拉刷新上拉加载更多并可切换线性流和瀑布流模式(1)

    摘要 最近项目有个列表页需要实现线性列表和瀑布流展示的切换,首先我想到的就是上 [RecyclerView],他本身已经很好的提供了三种布局方式,只是简单做个切换应该是很简单的事情,如果要用Recyc ...

  9. ListView下拉刷新上拉加载更多实现

    这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉 ...

随机推荐

  1. 修改本地数据库root权限密码

    方法1: 用SET PASSWORD命令 测试成功 首先登录MySQL @1——mysql DOS 窗口中. 格式:mysql> set password for 用户名@localhost = ...

  2. Samba 服务器介绍

    Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成.SMB(Server Messages Block,信息服务块)是一种在局域网上共享文件和打印机的一种通 ...

  3. int string convert

    C++ int与string的转化 int本身也要用一串字符表示,前后没有双引号,告诉编译器把它当作一个数解释.缺省 情况下,是当成10进制(dec)来解释,如果想用8进制,16进制,怎么办?加上前缀 ...

  4. light oj 1248 第六周E题(期望)

    E - 期望(经典问题) Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%lld & %llu   Descri ...

  5. HTML 基础元素

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. Scut:GameWebSocketHost 解析

    想使用 Scut 做的是一个短连接项目,所以先直接看 GameWebSocketHost 了. 先来看下 GameWebSocketHost 的成员: protected bool EnableHtt ...

  7. /etc/fstab自动挂载文件系统

    打开 /etc/fstab 文件 [root@www ~]# vi /etc/fstab 默认情况下,fstab中已经有了当前的分区配置,内容可能类似: # <file system> & ...

  8. 【转】TCP三次握手过程

    写的非常明白:http://www.cnblogs.com/rootq/articles/1377355.html TCP协议三次握手过程分析 TCP(Transmission Control Pro ...

  9. cf590B Chip 'n Dale Rescue Rangers

    B. Chip 'n Dale Rescue Rangers time limit per test 1 second memory limit per test 256 megabytes inpu ...

  10. 【用PS3手柄在安卓设备上玩游戏系列】连接手柄和设备

    背景 硬件要求1:PS3 手柄 + 手柄配套的USB线 硬件要求2:已经获得 ROOT 权限并且支持蓝牙的安卓设备 软件要求1:Sixaxis Compatibility Checker PS3 手柄 ...