为RecyclerView添加header和footer

目标

RecyclerView渐渐的取代了ListView,但是有一点它没有ListView方便,那就是不能添加header,所以我们只能自己实现,功能如下:

  • 手动添加删除Header和Footer
  • 提供加载更多接口

思路

实现该功能的核心在Adapter类,我们声明三种类型来区分header、footer、normal。

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

重写getItemViewType方法,根据当前mHeader和mFooter是否存在和position来判断当前的type

    @Override
    public int getItemViewType(int position) {
        if (mHeader == null && mFooter == null) {
            return TYPE_NORMAL;
        } else if (mHeader == null) {
            return position == getItemCount() - 1 ? TYPE_FOOTER : TYPE_NORMAL;
        } else if (mFooter == null) {
            return position == 0 ? TYPE_HEADER : TYPE_NORMAL;
        } else {
            if (position == 0) {
                return TYPE_HEADER;
            }
            if (position == getItemCount() - 1) {
                return TYPE_FOOTER;
            }
            return TYPE_NORMAL;
        }
    }

onCreateViewHolder()很简单,如下

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case TYPE_HEADER:
                return new HeaderViewHodler(mHeader);

            case TYPE_FOOTER:
                return new FooterViewHodler(mFooter);

            case TYPE_NORMAL:
                return new ItemViewHodler(mInflater.inflate(R.layout.item_layout, parent, false));

            default:
                return null;
        }
    }

提供onLoadMoreListener接口

    public interface onLoadMoreListener {
        public void onLoadMore(View footView);
    }

    ...

    public void setLoadMoreListener(onLoadMoreListener mLoadMoreListener) {
        this.mLoadMoreListener = mLoadMoreListener;
    }

接下来就是判断是否到达底部,如果到达了那就调用loadMore接口

    private void setupScrollListener() {
        mLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                Log.d("Debug", "count" + getItemCount() + "\nlast" + mLayoutManager.findLastVisibleItemPosition());
                if (!isLoading && mFooter != null && mLayoutManager.findLastVisibleItemPosition() == getItemCount() - 1 && mLoadMoreListener != null) {
                    isLoading = true;
                    mLoadMoreListener.onLoadMore(mFooter);
                }
            }
        });
    }

这里我们好需要写一个getRealPosition方法,因为可能我们需要点击一个item然后通过接口传递给外部当前的position,用户需要得到的是真正的数据位置,是除去header的(和footer无关,因为footer总是在最后一个位置,不会影响前面的位置)。

    private int getRealPosition(int position) {
        return mHeader == null ? position : position - 1;
    }

完整代码

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

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

    public interface onLoadMoreListener {
        public void onLoadMore(View footView);
    }

    public interface onItemClickListener {
        public void onItemClick(View view, int position);
    }

    private List<String> mData;

    private Context mContext;

    private LayoutInflater mInflater;

    private View mHeader;

    private View mFooter;

    private onLoadMoreListener mLoadMoreListener;

    private onItemClickListener mClickListener;

    private RecyclerView mRecyclerView;

    private boolean isLoading = false;

    private LinearLayoutManager mLayoutManager;

    public MyAdapter(Context context, List<String> data, RecyclerView recyclerView) {
        mContext = context;
        mData = data;
        mRecyclerView = recyclerView;
        mInflater = LayoutInflater.from(context);
        setupScrollListener();
    }

    private void setupScrollListener() {
        mLayoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
        mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                Log.d("Debug", "count" + getItemCount() + "\nlast" + mLayoutManager.findLastVisibleItemPosition());
                if (!isLoading && mFooter != null && mLayoutManager.findLastVisibleItemPosition() == getItemCount() - 1 && mLoadMoreListener != null) {
                    isLoading = true;
                    mLoadMoreListener.onLoadMore(mFooter);
                }
            }
        });
    }

    public void setLoading(boolean loading) {
        isLoading = loading;
    }

    public void setClickListener(onItemClickListener mClickListener) {
        this.mClickListener = mClickListener;
    }

    public void setLoadMoreListener(onLoadMoreListener mLoadMoreListener) {
        this.mLoadMoreListener = mLoadMoreListener;
    }

    public void setHeader(View header) {
        this.mHeader = header;
        notifyDataSetChanged();
    }

    public void setFooter(View footer) {
        this.mFooter = footer;
        notifyDataSetChanged();


    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case TYPE_HEADER:
                return new HeaderViewHodler(mHeader);

            case TYPE_FOOTER:
                return new FooterViewHodler(mFooter);

            case TYPE_NORMAL:
                return new ItemViewHodler(mInflater.inflate(R.layout.item_layout, parent, false));

            default:
                return null;
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int type = getItemViewType(position);
        if (type == TYPE_NORMAL) {
            ItemViewHodler viewHolder = (ItemViewHodler)holder;
            viewHolder.text.setText(mData.get(getRealPosition(position)));
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (mHeader == null && mFooter == null) {
            return TYPE_NORMAL;
        } else if (mHeader == null) {
            return position == getItemCount() - 1 ? TYPE_FOOTER : TYPE_NORMAL;
        } else if (mFooter == null) {
            return position == 0 ? TYPE_HEADER : TYPE_NORMAL;
        } else {
            if (position == 0) {
                return TYPE_HEADER;
            }
            if (position == getItemCount() - 1) {
                return TYPE_FOOTER;
            }
            return TYPE_NORMAL;
        }
    }

    @Override
    public int getItemCount() {
        return (mHeader == null ? 0 : 1) + (mFooter == null ? 0 : 1) + mData.size();
    }

    class ItemViewHodler extends RecyclerView.ViewHolder {

        public TextView text;

        public ItemViewHodler(final View itemView) {
            super(itemView);
            text = (TextView) itemView.findViewById(R.id.text);
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mClickListener != null) {
                        mClickListener.onItemClick(itemView, getRealPosition(getLayoutPosition()));
                    }
                }
            });
        }
    }

    class HeaderViewHodler extends RecyclerView.ViewHolder {

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

        public FooterViewHodler(final View itemView) {
            super(itemView);
        }
    }

    private int getRealPosition(int position) {
        return mHeader == null ? position : position - 1;
    }


}

效果图

这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值