RecyclerView添加Header和Footer

本篇博客借鉴了 亓斌 大神的, RecyclerView添加Header的正确方式

自己想做一个类似微信的联系人界面,想到的解决方案就是在recyclerView添加header和footer。
做出来的效果如下:(界面有些丑,轻喷)


添加footer的时候也遇到了坑,最开始直接修改了getItemViewType方法,获得footer类型,和onCreateViewHolder方法里面加入创建footer的ViewHolder
    @Override
    public int getItemViewType(int position) {
        if (mHeaderView == null) return TYPE_NORMAL;
        if (position == 0) return TYPE_HEADER;
        if (mFooterView == null) return TYPE_NORMAL;
        if (position == getItemCount() - 1) return TYPE_FOOTER;
        return TYPE_NORMAL;
    }
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
        if (mFooterView != null && viewType == TYPE_FOOTER) return new ViewHolder(mFooterView);
        if (mHeaderView != null && viewType == TYPE_HEADER) return new ViewHolder(mHeaderView);
        return onCreate(parent, viewType);
    }



做了10个假数据后,拖动只可以看到8条数据。想想肯定是总数getItemCount方法的返回值有问题了
    @Override
    public int getItemCount() {
        int itemCount = mDatas.size();
        if (mHeaderView != null ) {
            itemCount ++ ;
        }
        if (mFooterView != null) {
            itemCount ++;
        }
        return itemCount;
    }
修改后,继续重新运行,运行到recyclerView的第8个Item在拖动就报ClassCastException。
找了好久也没找到是哪里的问题,后来经过debug发现,在onBindViewHolder里面的第一行代码进行了对header类型的Item进行的return,想想自己也应该加上。
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        //防止出现ClassCastException
        if (getItemViewType(position) == TYPE_HEADER) return;
        if (getItemViewType(position) == TYPE_FOOTER) return;

        int pos = getRealPosition(viewHolder);
        T data = null;
        //对数据进行判空,以免出现异常
        if (mDatas != null && mDatas.size() > 0) {
            data = mDatas.get(pos);
            onBind(viewHolder, pos, data);
        }
        if (mListener != null) {
            final T finalData = data;
            final int finalPos = pos;
            viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mListener.onItemClick(finalPos, finalData);
                }
            });
        }
    }
由于自己做的是联系人,在增加联系人后对数据要进行重新绑定,所以自己添加了onBindData方法,对recyclerView的数据重新赋值。

整体代码如下:

public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    public static final int TYPE_HEADER = 0;
    public static final int TYPE_NORMAL = 1;
    public static final int TYPE_FOOTER = 2;

    public Context context;

    public List<T> mDatas;

    public BaseRecyclerAdapter(Context context, List<T> datas) {
        this.context = context;
        this.mDatas = datas;
    }

    private View mHeaderView;
    public View mFooterView;

    private OnItemClickListener mListener;

    public void setOnItemClickListener(OnItemClickListener listener) {
        mListener = listener;
    }

    /**
     * 只可以添加一次headerView
     * @param headerView
     */
    public void setHeaderView(View headerView) {
        mHeaderView = headerView;
        notifyItemInserted(0);
    }

    public View getHeaderView() {
        return mHeaderView;
    }

    /**
     * 只可以添加一次footView
     * @param footerView
     */
    public void setFooterView(View footerView) {
        mFooterView = footerView;
        notifyItemInserted(getItemCount());
    }

    public View getFooterView() {
        return mFooterView;
    }

    @Override
    public int getItemViewType(int position) {
        if (mHeaderView == null) return TYPE_NORMAL;
        if (position == 0) return TYPE_HEADER;
        if (mFooterView == null) return TYPE_NORMAL;
        if (position == getItemCount() - 1) return TYPE_FOOTER;
        return TYPE_NORMAL;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, final int viewType) {
        if (mFooterView != null && viewType == TYPE_FOOTER) return new ViewHolder(mFooterView);
        if (mHeaderView != null && viewType == TYPE_HEADER) return new ViewHolder(mHeaderView);
        return onCreate(parent, viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
        //防止出现ClassCastException
        if (getItemViewType(position) == TYPE_HEADER) return;
        if (getItemViewType(position) == TYPE_FOOTER) return;

        int pos = getRealPosition(viewHolder);
        T data = null;
        //对数据进行判空,以免出现异常
        if (mDatas != null && mDatas.size() > 0) {
            data = mDatas.get(pos);
            onBind(viewHolder, pos, data);
        }
        if (mListener != null) {
            final T finalData = data;
            final int finalPos = pos;
            viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mListener.onItemClick(finalPos, finalData);
                }
            });
        }
    }

    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);

        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if (manager instanceof GridLayoutManager) {
            final GridLayoutManager gridManager = ((GridLayoutManager) manager);
            gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return getItemViewType(position) == TYPE_HEADER
                            ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder viewHolder) {
        super.onViewAttachedToWindow(viewHolder);
        ViewGroup.LayoutParams lp = viewHolder.itemView.getLayoutParams();
        if (lp != null
                && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
            p.setFullSpan(viewHolder.getLayoutPosition() == 0);
        }
    }

    /**
     * 得到真正的位置position
     * @param holder
     * @return
     */
    public int getRealPosition(RecyclerView.ViewHolder holder) {
        int position = holder.getLayoutPosition();
        return mHeaderView == null ? position : position - 1;
    }
    /**
     * 得到recyclerView中的item总数
     */
    @Override
    public int getItemCount() {
        int itemCount = mDatas.size();
        if (mHeaderView != null ) {
            itemCount ++ ;
        }
        if (mFooterView != null) {
            itemCount ++;
        }
        return itemCount;
    }
    /**
     * 得到recyclerView中的真正数据总数
     */
    public int getRealItemCount(){
        return mDatas.size();
    }

    public abstract RecyclerView.ViewHolder onCreate(ViewGroup parent, final int viewType);

    public abstract void onBind(RecyclerView.ViewHolder viewHolder, int realPosition, T data);

    public abstract void bindDatas(List<T> allNewFriend);

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
    }

    public interface OnItemClickListener<T> {
        void onItemClick(int position, T data);
    }
}
使用方法:
public class AddressListPagerAdapter extends BaseRecyclerAdapter<Friend> {

    public AddressListPagerAdapter(Context context, List<Friend> datas) {
        super(context, datas);
    }

    @Override
    public RecyclerView.ViewHolder onCreate(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.address_list_item, parent, false);
        return new ViewHolder(itemView);
    }

    @Override
    public void onBind(RecyclerView.ViewHolder viewHolder, int realPosition, Friend data) {
        ((ViewHolder) viewHolder).tv_friend_name.setText(mDatas.get(realPosition).getUsername());
        RequestOptions requestOptions = new RequestOptions()
                .placeholder(R.drawable.head)
                .error(R.drawable.default_head);
        Glide.with(context).load(mDatas.get(realPosition).getHeaderImage())
                .apply(requestOptions)
                .into(((ViewHolder) viewHolder).iv_head_portrait);
    }

    @Override
    public void bindDatas(List<Friend> allNewFriend) {
        mDatas = allNewFriend;
    }

    public class ViewHolder extends BaseRecyclerAdapter.ViewHolder {

        private ImageView iv_head_portrait;
        private TextView tv_friend_name;

        public ViewHolder(View itemView) {
            super(itemView);
            iv_head_portrait = (ImageView) itemView.findViewById(R.id.iv_head_portrait);
            tv_friend_name = (TextView) itemView.findViewById(R.id.tv_friend_name);
        }
    }
}
添加Header和Footer直接调用,setHeaderView和setFooterView方法既可以,header和footer点击事件没有在recyclerView里面进行处理,需要自己进行设置,个人感觉脱离了recyclerView的header和footer的点击事件处理起来更好一些,个人观点可能有点片面,不过应该具体情况具体分析吧。
唯一的一点遗憾就是在onBind里面进行绑定数据的时候需要对viewHolder进行强转。还有这样的方法只能添加一个header和一个footer,如果想多添加,可以将对应的view添加到header和footer中。如果还是不能满足你的需求,可以借鉴 鸿洋_大神的方法
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值