1.概述
A flexible view for providing a limited window into a large data set.
官方解释:在有限的窗口展示大量数据集的流畅界面
RecyclerView提供了一种插拔式的体验,实现了高度的解耦,虽然比起ListView和GridView使用起来更麻烦,但是它异常的灵活。
(1)控制显示方式:通过布局管理器LayoutManager;
(2)控制Item间隔(可自定义绘制):通过ItemDecoration;
(3)控制Item增删动画:通过ItemAnimator;
(4)控制点击、长按事件:通过回调自己实现;
不熟悉RecyclerView使用的读者请参考:
http://blog.csdn.net/lmj623565791/article/details/45059587
RecyclerView虽然作为ListView的替代者有着较好的性能提升,但是ListView的一些常用功能却没有提供,比如我们平时会经常用到的addHeaderView,addFooterView。没有,我们就重写写喽。
2.实现
RecyclerView实现添加HeaderView和FooterView的核心就是在Adapter里面的onCreateViewHolder根据viewType来判断是列表项还是HeaderView或FooterView来分别加载不同的布局文件,当然viewType的判断规则也是由我们定义的。时候也不早了,来看看具体实现吧。
(1)重写RecyclerView(代码中解析)
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
/**
* Developer:chunsoft on 2016/10/31 10:25
* Email:chun_soft@qq.com
* Content:自定义RecycleView,增加头部和尾部的功能
*/
public class XRecycleView extends RecyclerView{
//存储HeadView
private ArrayList<View> mHeaderViews = new ArrayList<View>();
//存储FooterView
private ArrayList<View> mFooterViews = new ArrayList<View>();
private RecyclerView.Adapter mAdapter;
private RecyclerView.Adapter mWrapAdapter;
//各种返回类型标记
private static final int TYPE_HEADER = -101;
private static final int TYPE_FOOTER = -102;
private static final int TYPE_LIST_ITEM = -103;
public XRecycleView(Context context) {
super(context);
}
public XRecycleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public XRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context){
}
//注入Item的Adapter
@Override
public void setAdapter(Adapter adapter) {
mAdapter = adapter;
mWrapAdapter = new WrapAdapter(mHeaderViews,mFooterViews,adapter);
super.setAdapter(mWrapAdapter);
//registerAdapterDataObserver(observer);,在数据发生变化回调中重新生成,使用观察者模式,notifyDataSetChanged方法在RecyclerView里是final的
mAdapter.registerAdapterDataObserver(mDataObserver);
}
//添加头部
public void addHeaderView(View view){
mHeaderViews.clear();
mHeaderViews.add(view);
}
//添加尾部
public void addFooterView(View view){
mFooterViews.clear();
mFooterViews.add(view);
}
private final RecyclerView.AdapterDataObserver mDataObserver =
new RecyclerView.AdapterDataObserver(){
@Override
public void onChanged() {
mWrapAdapter.notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeChanged(positionStart,itemCount);
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
mWrapAdapter.notifyItemRangeChanged(positionStart,itemCount,payload);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeInserted(positionStart,itemCount);
}
@Override
public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
mWrapAdapter.notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
mWrapAdapter.notifyItemRangeRemoved(positionStart,itemCount);
}
};
//带头部和底部的Adapter
private class WrapAdapter extends android.support.v7.widget.RecyclerView.Adapter<ViewHolder>{
private Adapter mAdapetr;
private List<View> mHeaderViews;
private List<View> mFooterViews;
public WrapAdapter(List<View> mHeaderViews,List<View> mFooterViews,Adapter adapter){
this.mAdapetr = adapter;
this.mHeaderViews = mHeaderViews;
this.mFooterViews = mFooterViews;
}
public int getHeaderCount(){return this.mHeaderViews.size();};
public int getFooterCount(){return this.mFooterViews.size();};
public boolean isHeader(int position){
return position >= 0 && position < this.mHeaderViews.size();
}
public boolean isFooter(int position){
return position < getItemCount() && position >= getItemCount()-this.getFooterCount();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_HEADER){
return new CustomViewHolder(this.mHeaderViews.get(0));
}else if (viewType == TYPE_FOOTER){
return new CustomViewHolder(this.mFooterViews.get(0));
}else {
return this.mAdapetr.onCreateViewHolder(parent,viewType);
}
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if(isHeader(position)) return;
if(isFooter(position)) return;
int rePostion = position - getHeaderCount();
int itemCount = this.mAdapetr.getItemCount();
if (this.mAdapetr != null){
if (rePostion < itemCount){
this.mAdapetr.onBindViewHolder(holder,rePostion);
return;
}
}
}
@Override
public int getItemViewType(int position) {
if (isHeader(position)){
return TYPE_HEADER;
}else if(isFooter(position)){
return TYPE_FOOTER;
}
int rePostion = position - getHeaderCount();
int itemCount = this.mAdapetr.getItemCount();
if (rePostion < itemCount){
return this.mAdapetr.getItemViewType(position-getHeaderCount());
}
return TYPE_LIST_ITEM;
}
@Override
public int getItemCount() {
if (this.mAdapetr != null){
return getHeaderCount()+getFooterCount()+this.mAdapetr.getItemCount();
}else {
return getHeaderCount()+getFooterCount();
}
}
@Override
public void registerAdapterDataObserver(AdapterDataObserver observer) {
if (this.mAdapetr != null){
this.mAdapetr.registerAdapterDataObserver(observer);
}
}
//对注册的observer进行解注册
@Override
public void unregisterAdapterDataObserver(AdapterDataObserver observer) {
if (this.mAdapetr != null){
this.mAdapetr.unregisterAdapterDataObserver(observer);
}
}
@Override
public void onViewDetachedFromWindow(ViewHolder holder) {
if (holder.getItemViewType() == TYPE_HEADER){
super.onViewDetachedFromWindow(holder);
}else if(holder.getItemViewType() == TYPE_FOOTER){
super.onViewDetachedFromWindow(holder);
}else {
this.mAdapetr.onViewDetachedFromWindow(holder);
}
}
private class CustomViewHolder extends ViewHolder{
public CustomViewHolder(View itemView) {
super(itemView);
}
}
}
}
(2)Activity中用起来
//头部布局
View mHeaderView = LayoutInflater.from(getActivity()).inflate(R.layout.home_header,null);
mRecyclerView.setHasFixedSize(true);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.addHeaderView(mHeaderView);
mAdapter = new HomeAdapter(getActivity());
mAdapter.setOnItemClickListtener(mOnItemClickListtener);
mRecyclerView.setAdapter(mAdapter);
(3)注意事项
如果你的RecyclerView使用Grid类型列表在设置Adapter后需要调用这个方法,根据当前Item类型来判断占据的横向格数,这也是Adapter里面实现isHeader和isFooter的缘故。
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
return (adapter.isHeader(position) || adapter.isFooter(position)) ? gridLayoutManager.getSpanCount() : 1;
}
});
我将retrofit+rxjava+rxandroid+okHttp+mvp设计模式结合,和一些流行开源库写了一个简单的Android基础开发框架,里面包括本文内容,会不断加入新的内容:
GitHub地址:https://github.com/chunonesoft/BaseFramework