上篇文章介绍了RecyclerView的基本使用,今天我们来着重实践一下RecyclerView瀑布流的效果以及上拉加载的功能;如果您对RecyclerView还不太了解的话请先阅读下上篇文章【Android】RecyclerView详解(一);
首先我们要实现下面这个效果:
compile 'com.android.support:recyclerview-v7:23.4.0'
compile 'com.android.support:cardview-v7:23.4.0'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.squareup.picasso:picasso:2.5.2'
"http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
.support.v7.widget.RecyclerView
android:id="@+id/rv_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:cardBackgroundColor="@android:color/white"
app:cardCornerRadius="5dp"
app:cardElevation="5dp"
app:contentPadding="10dp" >
<ImageView
android:id="@+id/item_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
/>
android.support.v7.widget.CardView>
class MyAdapter extends RecyclerView.Adapter
{
public List datas = null;
public MyAdapter(List datas)
{
this.datas = datas;
}
@Override
public int getItemCount()
{
return datas.size();
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, int i)
{
//加载图片
ImageLoader.getInstance().displayImage(datas.get(i), ((MyViewHolder)viewHolder).image);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int position)
{
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item, viewGroup, false);
ViewHolder vh = new MyViewHolder(view);
return vh;
}
}
public static class MyViewHolder extends RecyclerView.ViewHolder
{
public ImageView image;
public MyViewHolder(View itemView)
{
super(itemView);
image = (ImageView)itemView.findViewById(R.id.item_image);
}
}
recyclerView = (RecyclerView)findViewById(R.id.rv_view);
// 设置瀑布流布局
StaggeredGridLayoutManager stagManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
recyclerView.setLayoutManager(stagManager);
//模拟数据
for (int i = 0; i < ImageURL.length; i++)
{
datas.add(ImageURL[i]);
}
MyAdapter adapter = new MyAdapter(datas);
recyclerView.setAdapter(adapter);
当然这可能无法满足项目使用,一般都会结合上拉和下拉一起使用,关于下拉刷新这里不作介绍,比较简单,这里重点介绍一下RecyclerView各种layoutManager上拉加载功能,此处参考_区长的实现思路,略作改动,下面一起来看下如何实现的吧!
public interface OnLoadMoreListener {
/**
* 加载更多前回调,比如显示Footer的操作
*/
void onStart();
/**
* 加载更多业务处理,如网络请求数据
*/
void onLoadMore();
/**
* 由于onLoadMore可能是异步调用的,所以onFinish需要手动调用,完成数据的刷新,隐藏Footer等
* @param list onLoadMore中返回的数据
*/
void onFinish(List list);
}
- 实现上拉加载主要还是要为RecyclerView添加头和尾,目前普遍的方式是根据 getItemViewType方法,依据返回的type类型来加载不同的布局来实现;
@Override
public int getItemViewType(int type)
public abstract class OnRecyclerViewScrollListener<T extends String> extends RecyclerView.OnScrollListener implements OnLoadMoreListener<T> {
public static enum layoutManagerType {
LINEAR_LAYOUT,
GRID_LAYOUT,
STAGGERED_GRID_LAYOUT
}
protected layoutManagerType mLayoutManagerType;
private boolean mIsLoadingMore = false;
public boolean isLoadingMore() {
return mIsLoadingMore;
}
public void setLoadingMore(boolean loadingMore) {
mIsLoadingMore = loadingMore;
}
private int[] lastPositions;
private int lastVisibleItemPosition;
private int currentScrollState = 0;
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
//获取当前layoutManager类型
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
//指定当前layoutManager类型
if (mLayoutManagerType == null) {
if (layoutManager instanceof LinearLayoutManager) {
mLayoutManagerType = layoutManagerType.LINEAR_LAYOUT;
} else if (layoutManager instanceof GridLayoutManager) {
mLayoutManagerType = layoutManagerType.GRID_LAYOUT;
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
mLayoutManagerType = layoutManagerType.STAGGERED_GRID_LAYOUT;
} else {
throw new RuntimeException("Unsupported LayoutManager used. Valid ones are LinearLayoutManager, GridLayoutManager and StaggeredGridLayoutManager");
}
}
switch (mLayoutManagerType) {
case LINEAR_LAYOUT:
//找到当前显示的所有item的最后一项
lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition();
break;
case GRID_LAYOUT:
//找到当前显示的所有item的最后一项
lastVisibleItemPosition = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition();
break;
case STAGGERED_GRID_LAYOUT:
//找到当前显示的所有item的最后一项
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
if (lastPositions == null) {
lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];
}
staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);
lastVisibleItemPosition = findMax(lastPositions);
break;
default:
break;
}
}
/**
* recyclerView滑动状态改变时调用此方法
* @param recyclerView
* @param newState
*/
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
currentScrollState = newState;
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
int visibleItemCount = layoutManager.getChildCount();
int totalItemCount = layoutManager.getItemCount();
if (visibleItemCount > 0 && currentScrollState == RecyclerView.SCROLL_STATE_IDLE
&& lastVisibleItemPosition >= totalItemCount - 1) {
if (!isLoadingMore()){
mIsLoadingMore =true;
onStart();
onLoadMore();
}
}
}
private int findMax(int[] lastPositions) {
int max = lastPositions[0];
for (int value : lastPositions) {
if (value > max) {
max = value;
}
}
return max;
}
}
public abstract class RecyclerViewAdapter<T extends String> extends RecyclerView.Adapter<RecyclerView.ViewHolder>
{
/**
* 不同的布局类型,0代表头部,1代表尾部,2代表普通布局
*/
public interface Item
{
int TYPE_HEADER = 0;
int TYPE_FOOTER = 1;
int TYPE_NORMAL = 2;
}
//数据源
private List list = null;
//头部layout资源id
private int headerViewRes;
//尾部layout资源id
private int footerViewRes;
//当前是否有头
private boolean hasHeader = false;
//当前是否有尾
private boolean hasFooter = false;
public List getList()
{
return list;
}
public void setList(List list)
{
this.list = list;
}
/**
* 判断position位置的item是否是头head
* @param position
* @return
*/
public boolean isHeader(int position)
{
return hasHeader() && position == 0;
}
/**
* 判断position位置的item是否是尾foot
* @param position
* @return
*/
public boolean isFooter(int position)
{
if (hasHeader())
{
return hasFooter() && position == list.size() + 1;
} else
{
return hasFooter() && position == list.size();
}
}
public boolean hasHeader()
{
return hasHeader;
}
public boolean hasFooter()
{
return hasFooter;
}
public int getHeaderView()
{
return headerViewRes;
}
public int getFooterView()
{
return footerViewRes;
}
/**
* 设置头部layout布局文件
*
* @param headerViewRes
*/
public void setHeaderView(int headerViewRes)
{
if (headerViewRes != 0)
{
if (!hasHeader())
{
this.headerViewRes = headerViewRes;
this.hasHeader = true;
notifyItemInserted(0);
} else
{
this.headerViewRes = headerViewRes;
notifyDataSetChanged();
}
} else
{
if (hasHeader())
{
this.hasHeader = false;
notifyItemRemoved(0);
}
}
}
/**
* 设置尾部layout布局文件
*
* @param footerViewRes
*/
public void setFooterView(int footerViewRes)
{
if (footerViewRes != 0)
{
if (!hasFooter())
{
this.footerViewRes = footerViewRes;
this.hasFooter = true;
if (hasHeader())
{
notifyItemInserted(list.size() + 1);
} else
{
notifyItemInserted(list.size());
}
} else
{
this.footerViewRes = footerViewRes;
notifyDataSetChanged();
}
} else
{
if (hasFooter())
{
this.hasFooter = false;
if (hasHeader())
{
notifyItemRemoved(list.size() + 1);
} else
{
notifyItemRemoved(list.size());
}
}
}
}
/**
* 构造函数
* @param list
*/
public RecyclerViewAdapter(List list) {
this.list = list;
}
/**
* 构造函数
* @param list
* @param headerViewRes
*/
public RecyclerViewAdapter(List list, int headerViewRes) {
this.list = list;
setHeaderView(headerViewRes);
}
/**
* 构造函数
* @param list
* @param headerViewRes
* @param footerViewRes
*/
public RecyclerViewAdapter(List list, int headerViewRes,int footerViewRes)
{
this.list = list;
setHeaderView(headerViewRes);
setFooterView(footerViewRes);
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
{
/**
* 根据不同的类型加载不同的ViewHolder
*/
if (hasHeader() && viewType == Item.TYPE_HEADER) {
View v = LayoutInflater.from(parent.getContext()).inflate(getHeaderView(), parent, false);
return new HeaderViewHolder(v);
} else if (hasFooter() && viewType == Item.TYPE_FOOTER) {
View v = LayoutInflater.from(parent.getContext()).inflate(getFooterView(), parent, false);
return new FooterViewHolder(v);
} else {
return onCreateHolder(parent, viewType);
}
}
/*以下是抽象出来的公共方法,用于实现普通布局的处理*/
public abstract RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType);
protected abstract void onBindHeaderView(View headerView);
protected abstract void onBindFooterView(View footerView);
protected abstract void onBindItemView(RecyclerView.ViewHolder holder, T item);
/*抽象结束*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
/**
* 根据类型来绑定数据
*/
if (getItemViewType(position) == Item.TYPE_HEADER) {
HeaderViewHolder headerHolder = (HeaderViewHolder) holder;
View headerView = headerHolder.itemView;
onBindHeaderView(headerView);
} else if (getItemViewType(position) == Item.TYPE_FOOTER) {
FooterViewHolder footerHolder = (FooterViewHolder) holder;
View footerView = footerHolder.itemView;
onBindFooterView(footerView);
} else {
T i = getItemByPosition(position);
onBindItemView(holder, i);
}
}
/**
* 返回item数量
* @return
*/
@Override
public int getItemCount() {
int count = 0;
count += (hasHeader() ? 1 : 0);
count += (hasFooter() ? 1 : 0);
count += list.size();
return count;
}
/**
* 获取position位置的数据值
* @param position
* @return
*/
protected T getItemByPosition(int position) {
if (hasHeader()) {
return list.get(position - 1);
} else {
return list.get(position);
}
}
@Override
public int getItemViewType(int position)
{
int size = list.size();
if (hasHeader()) {
//包含头部并且position为0时返回Header类型
if (position == 0) {
return Item.TYPE_HEADER;
} else {
if (position == size + 1) {
return Item.TYPE_FOOTER;
} else {
return Item.TYPE_NORMAL;
}
}
} else {
if (position == size) {
return Item.TYPE_FOOTER;
} else {
return Item.TYPE_NORMAL;
}
}
}
/**
* 头部viewhodler
*/
static class HeaderViewHolder extends RecyclerView.ViewHolder {
public HeaderViewHolder(View itemView) {
super(itemView);
}
}
/**
* 尾部viewhodler
*/
static class FooterViewHolder extends RecyclerView.ViewHolder {
public FooterViewHolder(View itemView) {
super(itemView);
}
}
}
我们在使用时只需要继承RecyclerViewAdapter,来实现自己需要的adapter,下面我们分别来实现一下,看看效果;
LinearLayoutAdapter
public abstract class LinearLayoutAdapter extends RecyclerViewAdapter
{
public LinearLayoutAdapter(List list)
{
super(list);
}
public LinearLayoutAdapter(List list, int headerViewRes)
{
super(list, headerViewRes);
}
public LinearLayoutAdapter(List list, int headerViewRes, int footerViewRes)
{
super(list, headerViewRes, footerViewRes);
}
}
public class MyLinearAdapter extends LinearLayoutAdapter
{
public MyLinearAdapter(List list)
{
super(list);
}
public MyLinearAdapter(List list, int headerViewRes)
{
super(list, headerViewRes);
}
public MyLinearAdapter(List list, int headerViewRes, int footerViewRes)
{
super(list, headerViewRes, footerViewRes);
}
@Override
public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType)
{
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
return new ItemViewHolder(view);
}
@Override
protected void onBindHeaderView(View headerView)
{
//头部绑定后进行一些处理操作
}
@Override
protected void onBindFooterView(View footerView)
{
//尾部绑定后进行一些处理操作
}
@Override
protected void onBindItemView(RecyclerView.ViewHolder holder, String item)
{
ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
Picasso.with(holder.itemView.getContext()).load(item).into(itemViewHolder.icon);
}
static class ItemViewHolder extends RecyclerView.ViewHolder {
ImageView icon;
public ItemViewHolder(View itemView) {
super(itemView);
icon = (ImageView) itemView.findViewById(R.id.item_image);
}
}
}
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
adapter = new MyLinearAdapter(datas);
recyclerView.setAdapter(adapter);
recyclerView.addOnScrollListener(new OnRecyclerViewScrollListener(){
@Override
public void onStart() {
adapter.setFooterView(R.layout.footer);
if (adapter.hasHeader()){
recyclerView.smoothScrollToPosition(adapter.getItemCount()+1);
}else{
recyclerView.smoothScrollToPosition(adapter.getItemCount());
}
}
@Override
public void onLoadMore() {
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
//手动调用onFinish()
onFinish(arrayList);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
@Override
public void onFinish(List contents) {
Message message=Message.obtain();
message.obj=contents;
handler.sendMessage(message);
setLoadingMore(false);
}
});
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg)
{
List<String> list= (List<String>) msg.obj;
adapter.getList().addAll(list);
adapter.notifyDataSetChanged();
adapter.setFooterView(0);
}
};
public abstract class GridLayoutAdapter<T extends String> extends RecyclerViewAdapter {
public GridLayoutAdapter(List list) {
super(list);
}
public GridLayoutAdapter(List list, int headerViewRes) {
super(list, headerViewRes);
}
public GridLayoutAdapter(List list, int headerViewRes, int footerViewRes) {
super(list, headerViewRes, footerViewRes);
}
private GridSpanSizeLookup mGridSpanSizeLookup;
private GridLayoutManager gridManager;
@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
gridManager = ((GridLayoutManager) manager);
if (mGridSpanSizeLookup == null) {
mGridSpanSizeLookup = new GridSpanSizeLookup();
}
gridManager.setSpanSizeLookup(mGridSpanSizeLookup);
}
}
class GridSpanSizeLookup extends GridLayoutManager.SpanSizeLookup {
@Override
public int getSpanSize(int position) {
if (isHeader(position) || isFooter(position)) {
//包含头部和尾部时合并成一行显示,getSpanCount代表列数
return gridManager.getSpanCount();
}
return 1;
}
}
}
public class MyGridAdapter extends GridLayoutAdapter{
public MyGridAdapter(List list, int headerViewRes) {
super(list, headerViewRes);
}
public MyGridAdapter(List list) {
super(list);
}
public MyGridAdapter(List list, int headerViewRes, int footerViewRes) {
super(list, headerViewRes, footerViewRes);
}
@Override
public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
return new ItemViewHolder(view);
}
@Override
protected void onBindHeaderView(View headerView) {
//这是HeadView数据绑定的过程
}
@Override
protected void onBindFooterView(View footerView) {
//这是FootView数据绑定的过程
}
@Override
protected void onBindItemView(RecyclerView.ViewHolder holder, String item)
{
ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
Picasso.with(holder.itemView.getContext()).load(item).into(itemViewHolder.icon);
}
static class ItemViewHolder extends RecyclerView.ViewHolder {
ImageView icon;
public ItemViewHolder(View itemView) {
super(itemView);
icon = (ImageView) itemView.findViewById(R.id.item_image);
}
}
}
public abstract class StaggeredGridLayoutAdapter<T extends String> extends RecyclerViewAdapter<T> {
public StaggeredGridLayoutAdapter(List list) {
super(list);
}
public StaggeredGridLayoutAdapter(List list, int headerViewRes) {
super(list, headerViewRes);
}
public StaggeredGridLayoutAdapter(List list, int headerViewRes, int footerViewRes) {
super(list, headerViewRes, footerViewRes);
}
@Override
public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
super.onViewAttachedToWindow(holder);
if (isStaggeredGridLayout(holder)) {
handleLayoutIfStaggeredGridLayout(holder, holder.getLayoutPosition());
}
}
private boolean isStaggeredGridLayout(RecyclerView.ViewHolder holder) {
ViewGroup.LayoutParams layoutParams = holder.itemView.getLayoutParams();
if (layoutParams != null && layoutParams instanceof StaggeredGridLayoutManager.LayoutParams) {
return true;
}
return false;
}
protected void handleLayoutIfStaggeredGridLayout(RecyclerView.ViewHolder holder, int position) {
if (isHeader(position) || isFooter(position)) {
StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
//有头尾时合并一列显示
p.setFullSpan(true);
}
}
}
public class MyRecAdapter extends StaggeredGridLayoutAdapter{
public MyRecAdapter(List list, int headerViewRes) {
super(list, headerViewRes);
}
public MyRecAdapter(List list) {
super(list);
}
public MyRecAdapter(List list, int headerViewRes, int footerViewRes) {
super(list, headerViewRes, footerViewRes);
}
@Override
public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) {
View view=LayoutInflater.from(parent.getContext()).inflate(R.layout.item,parent,false);
return new ItemViewHolder(view);
}
@Override
protected void onBindHeaderView(View headerView) {
//这是HeadView数据绑定的过程
}
@Override
protected void onBindFooterView(View footerView) {
//这是FootView数据绑定的过程
}
@Override
protected void onBindItemView(RecyclerView.ViewHolder holder, String item)
{
ItemViewHolder itemViewHolder = (ItemViewHolder) holder;
Picasso.with(holder.itemView.getContext()).load(item).into(itemViewHolder.icon);
}
static class ItemViewHolder extends RecyclerView.ViewHolder {
ImageView icon;
public ItemViewHolder(View itemView) {
super(itemView);
icon = (ImageView) itemView.findViewById(R.id.item_image);
}
}
}
记录下学习过程,希望能帮到您!源码下载