RecyclerView添加Header和Footer的方法

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值