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"去掉 ...
随机推荐
- Uva 120 - Stacks of Flapjacks(构造法)
UVA - 120 Stacks of Flapjacks Time Limit: 3000MS Memory Limit: Unknown 64bit IO Format: %lld &a ...
- 【Android】listview优化
http://www.cnblogs.com/over140/archive/2011/03/23/1991100.html http://blog.sina.com.cn/s/blog_5fc933 ...
- [EXCEL] 在单元格中自动输入时间和日期
选中需输入的单元格,直接按下“Ctrl+:”组合键可输入当前日期:如果直接按下“Ctrl+Shift+:”组合键即可输入当前时间:当然也可以在单元格中先输入其他文字然后再按以上组合键,如先输入“当前时 ...
- Qt经典—线程、事件与Qobject(耳目一新)
介绍 You’re doing it wrong. — Bradley T. Hughes 线程是qt channel里最流行的讨论话题之一.许多人加入了讨论并询问如何解决他们在运行跨线程编程时所遇到 ...
- 【HDOJ】1558 Segment set
并查集+计算几何. /* 1558 */ #include <cstdio> #include <cstring> #include <cstdlib> #defi ...
- POJ1942 Paths on a Grid(组合)
题目链接. 分析: #include <cstdio> #include <iostream> #include <map> #include <cstrin ...
- GCC依赖库顺序问题
今天在把linux下做的ipmsg移植到windows过程中,因为包含了一个开源库SimpleSocket,而这个库又引用了winsock2,没太注意就写下了下面的makefile: g++ -o t ...
- C#文本转语音并保存wav和MP3文件
回顾上次写博客至今都有4个多月了,最近工作比较的忙没时间写博文.以后会多坚持写博文,与大家分享下最近遇到的问题.最近因为项目需要,研究了下用C#开发TTS.下面把大体的思路给大家说说,希望对大家有所帮 ...
- Generate Parentheses——LeetCode
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- Java学习日记 I/O
File类1.String[] list() 返回一个目录下文件和文件夹路径的字符串数组2.File[] listFiles() 以File类对象数组,返回目录下的所有文件和文件夹3.isDirect ...