RecycleView 滑动到底部,加载更多
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 滑动到底部,加载更多的更多相关文章
- 滚动到底部加载更多及下拉刷新listview的使用
最新内容建议直接访问原文:滚动到底部加载更多及下拉刷新listview的使用 本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用. 该ListView优点包括:a. 可自定义下 ...
- XRecyclerView:实现下拉刷新、滚动到底部加载更多以及添加header功能的RecyclerView
介绍: 一个实现了下拉刷新,滚动到底部加载更多以及添加header功能的的RecyclerView.使用方式和RecyclerView完全一致,不需要额外的layout,不需要写特殊的adater. ...
- ionic 上拉加载更多&瀑布流加载&滚动到底部加载更多 主意事项
首先下拉刷新的代码是这样的,标红的地方为关键代码 <html> <head> <meta charset="utf-8"> <meta n ...
- jquery页面滑到底部加载更多
$(window).scroll(function(){ var _scrolltop = $('body').scrollTop();if(_scrolltop+_winHeight>_doc ...
- Jquery实现滚动到底部加载更多(最原始)
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8& ...
- vant list列表滚动到底部加载更多会滚动到顶部问题
如果使用异步加载数据并使用了vant中的toast做加载中提示,则有可能会导致列表滚动高度为0,也就是回到了顶部.只要在list加载回调里不使用toast就可以避免这个问题.
- JQuery ajax 滚动底部加载更多
<%@ Page Language="C#" %> <%@ Import Namespace="System.IO" %> <%@ ...
- RecyclerView实例-实现可下拉刷新上拉加载更多并可切换线性流和瀑布流模式(1)
摘要 最近项目有个列表页需要实现线性列表和瀑布流展示的切换,首先我想到的就是上 [RecyclerView],他本身已经很好的提供了三种布局方式,只是简单做个切换应该是很简单的事情,如果要用Recyc ...
- ListView下拉刷新上拉加载更多实现
这篇文章将带大家了解listview下拉刷新和上拉加载更多的实现过程,先看效果(注:图片中listview中的阴影可以加上属性android:fadingEdge="none"去掉 ...
随机推荐
- PHP图形计算器(计算三角形矩形周长面积)
运用PHP面向对象的知识设计一个图形计算器,同时也运用到了抽象类知识,这个计算器可以计算三角形的周长和面积以及矩形的周长和面积.本图形计算器有4个页面:1.PHP图形计算器主页index.php; ...
- 【行为型】TemplateMethod模式
模板方法意图是为算法定义好骨架结构,并且其中的某些步骤延迟到子类实现.该模式算是较为简单的一种设计模式.在实际中,应用也较为频繁.模式的类关系图参考如下: 模式的编码结构参考如下: namespace ...
- Delphi-Concat 函数
函数名称 Concat 所在单元 System 函数原型 function Concat ( const String1 {,String2 ...} : string ) : string; 函数功 ...
- ASP.NET 无权访问所请求的资源。请考虑对 ASP.NET 请求标识授予访问此资源的权限。
如题,在编译程序时,没有问题,但是通过iis设置的网站进入时,报如上错误.asp.net有个运行账户,一般情况下iis5为aspnet,iis6为network service,在iis里面确认一下是 ...
- iOS Block 用法 (1)-once again
Block简介: Block的实际行为和Function很像,最大的差别是在可以存取同一个Scope的变量值.Block实体形式如下: ^(传入参数列){行为主体}; Block实体开头是“^”,接着 ...
- Android JSON,Gson,fastjson实现比较
activity_main.xml <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android&qu ...
- h.264码率控制
h.264的码流传输是基于目前有限的网络带宽来进行的,以目前的压缩效率来说,运动不算剧烈.细节不多的影像,在720p的情况下,1000kbps压缩损耗较少(psnr较大),能达到比较好的观赏效果,10 ...
- jstat(JVM Statistics Monitoring Tool)
功能 用于监视虚拟机各种运行状态信息的命令行工具.它可以显示本地或远程虚拟机进程中的类装载.内存.垃圾收集.JIT编译等运行数据,在没有GUI图形界面,只提供了纯文本控制台环境的服务器上,它将是运 ...
- Nodejs in Visual Studio Code 05.Swig+Bootstrap
1. 开始 准备好Express+Swig的练习代码:https://github.com/Mengkzhaoyun/nodepractise 准备好AdminLTE后台管理模版:https://ww ...
- Windows 10 代理上网用户的正确使用姿势
1.找不到IE,如何使用IE来配置局域网代理 打开Edge浏览器,点击选项,找到“使用Internet Explorer打开” 接下来可以使用熟练的姿势设置IE局域网代理上网了 2.Windows ...