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. JS判断鼠标从哪个方向进入DIV容器

    写的不够高大上 , 不要介意哦... Js: //进去 $(".flash").bind("mouseenter",function(e){ /** the w ...

  2. python的bind函数

    # -*- coding:utf-8 -*- class Functor(object): def __init__(self, func, index=0, *args, **kwargs): se ...

  3. centos下安装cdh5

    http://www.aboutyun.com/thread-9075-1-1.html 基本参考这个   yum clean all yum update     1.保证selinux关闭  /e ...

  4. (转)JavaScript 开发者经常忽略或误用的七个基础知识点

    英文原文:7 JavaScript Basics Many Developers Aren't Using (Properly) JavaScript 本身可以算是一门简单的语言,但我们也不断用智慧和 ...

  5. chrome代理服务器设置

    在百度的内网很难访问chrome的相关站点,如果安装一些chrome的插件很不方便,所以呢,研究了一下chrome浏览器的代理模式,FQ安装插件. Chrome设置代理服务器的方法大体有几种: 1. ...

  6. MappedByteBuffer高速缓存文件、RandomAccessFile随机访问

    说到高速缓存存储,处理读写文件,那就不得不说MappedByteBuffer. 看了好多文章以后写一下自己的总结. 在这里先介绍一下相关的类与方法. 先说一下Buffer.ByteBuffer.Map ...

  7. elk 发送zabbix告警

  8. static用法一

    #include "stdafx.h" #include "string.h" struct student { int num; ]; char sex; } ...

  9. 黑马程序员_Java基础常识

    一.基础常识 1,软件开发 1)什么是软件?软件:一系列按照特定顺序组织的计算机数据和指令的集合. 常见的软件 系统软件 如:DOS,windows,Linux等. 应用软件: 如:扫雷,迅雷,QQ等 ...

  10. [Design Pattern] Command Pattern 简单案例

    Command Pattern, 即命令模式,把一个命令包裹在一个对象里面,将命令对象传递给命令的执行方,属于行为类的设计模式 下面是命令模式的一个简单案例. Stock 代表被操作的对象.Order ...