如何为Recyclerview写一个通用的adapter

来源:互联网 发布:知思索的意思 编辑:程序博客网 时间:2024/09/21 09:28

如何写一个通用的RecyclerView.adapter

项目源码地址:https://github.com/jiang111/SuperRecyclerViewAdapter
欢迎star和fork

随着需求的不断修改,在项目中越来越流行使用recyclerview。
那么如何构建出一个通用的adapter来提高我们的快速开发能力。
下面我们就来看看如何构建出一个完善的baseadapter。

1.分析

想要构建出一个很nice的adapter,那你必须得熟悉recyclerview.adapter的执行流程,以及一些常用的方法吧。 通过分析,我们知道adapter中几个主要的方法。

*1. onCreateViewHolder() //用来创建一个viewholder(viewholder必须继承recyclerview.viewholder)

*2. onBindViewHolder() //用来根据当前item的位置进行数据绑定。

*3. getItemViewType() //返回你当前的adapter里有几种item

*4. getItemCount() //返回item的总个数

*5. 还有就是ViewHolder这个类 ,这个类主要用于拿到item中的相关控件

2.实战

既然 viewholder的作用主要是拿到item中相关控件, 那我们完全可以写一个通用的viewholder然后提供一个getview()的方法,让adapter去拿相应的view.进行设置值。
看代码

public class BaseViewHolder extends RecyclerView.ViewHolder {    protected final SparseArray<View> mViews;    protected View mConvertView;    public BaseViewHolder(View itemView) {        super(itemView);        mViews = new SparseArray<>();        mConvertView = itemView;    }    /**     * 通过控件的Id获取对应的控件,如果没有则加入mViews,则从item根控件中查找并保存到mViews中     *     * @param viewId     * @return     */    public <T extends View> T getView(@IdRes int viewId) {        View view = mViews.get(viewId);        if (view == null) {            view = mConvertView.findViewById(viewId);            mViews.put(viewId, view);        }        return (T) view;    }    public View getmConvertView() {        return mConvertView;    }}

下面我们的adapter只需要使用BaseViewHolder,就可以了, 不需要在新建viewholder了。

public abstract class BaseAdapter<M> extends RecyclerView.Adapter<BaseViewHolder> {    protected List<M> mLists;    protected Context mContext;    protected int layoutID;    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {        this.onItemClickListener = onItemClickListener;    }    private OnItemClickListener onItemClickListener;    public BaseAdapter(List<M> mLists, Context mContext, int layoutID) {        this.mLists = mLists;        this.mContext = mContext;        this.layoutID = layoutID;    }    public List<M> getmLists() {        return mLists;    }    @Override    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        BaseViewHolder holder = new BaseViewHolder(LayoutInflater.from(mContext).inflate(layoutID, parent, false));        return holder;    }    @Override    public void onBindViewHolder(BaseViewHolder holder, final int position) {        if (onItemClickListener != null) {            holder.getmConvertView().setClickable(true);            holder.getmConvertView().setOnClickListener(new View.OnClickListener() {                @Override                public void onClick(View v) {                    onItemClickListener.onItemClick(position);                }            });        }        onBindView(holder, position);    }    protected abstract void onBindView(BaseViewHolder holder, int position);    @Override    public int getItemCount() {        return mLists == null ? 0 : mLists.size();    }}

onCreateViewHolder方法我们以及写好了,只需要再暴露出onBindView这个抽象方法即可。
然后我们在我们的activity中。

mRecyclerView.setAdapter(new BaseAdapter<Character>(mLists, this, R.layout.item_main) {            @Override            protected void onBindView(BaseViewHolder holder, final int position) {                TextView mTitle = holder.getView(R.id.item_tv);                mTitle.setText(this.getmLists().get(position) + "");            }        });

这样的adapter不包含head和foot的。
那我们再写一个包含head和foot的adapter

public abstract class BaseHeadFootAdapter<M> extends RecyclerView.Adapter<BaseViewHolder> {    protected List<M> mLists;    protected Context mContext;    protected int layoutID;    private boolean isHasHeader = false;    private boolean isHasFooter = false;    private int headerLayoutID;    private int footerLayoutID;    protected static final int TYPE_HEADER = -2;    protected static final int TYPE_ITEM = -1;    protected static final int TYPE_FOOTER = -3;    public BaseHeadFootAdapter(List<M> mLists, Context mContext, int layoutID) {        this.mLists = mLists;        this.mContext = mContext;        this.layoutID = layoutID;    }    public BaseHeadFootAdapter(int layoutID, Context mContext, List<M> mLists, int headerLayoutID, int footerLayoutID) {        this.layoutID = layoutID;        this.mContext = mContext;        this.mLists = mLists;        addHeader(headerLayoutID);        addFooter(footerLayoutID);    }    @Override    public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        BaseViewHolder holder;        if (viewType == TYPE_HEADER) {            if (headerLayoutID == 0) {                throw new NullPointerException("header 资源ID尚未初始化");            } else {                holder = new BaseViewHolder(LayoutInflater.from(mContext).inflate(headerLayoutID, parent, false));            }        } else if (viewType == TYPE_FOOTER) {            if (footerLayoutID == 0) {                throw new NullPointerException("footer 资源ID尚未初始化");            } else {                holder = new BaseViewHolder(LayoutInflater.from(mContext).inflate(footerLayoutID, parent, false));            }        } else {            holder = new BaseViewHolder(LayoutInflater.from(mContext).inflate(layoutID, parent, false));        }        return holder;    }    @Override    public void onBindViewHolder(BaseViewHolder holder, final int position) {        if (isHasFooter) {            if (isFooterPosition(position)) {                onBindFooterView(holder, position);                return;            }        }        if (isHasHeader) {            if (isHeaderPosition(position)) {                onBindHeaderView(holder, position);                return;            } else {                onBindView(holder, position - 1);            }        } else {            onBindView(holder, position);        }    }    protected abstract void onBindHeaderView(BaseViewHolder holder, int position);    protected abstract void onBindFooterView(BaseViewHolder holder, int position);    protected abstract void onBindView(BaseViewHolder holder, int position);    public void addHeader(@LayoutRes int headLayoutID) {        if (headLayoutID == 0)            return;        this.headerLayoutID = headLayoutID;        isHasHeader = true;    }    public List<M> getmLists() {        return mLists;    }    public void addFooter(@LayoutRes int footLayoutID) {        if (footLayoutID == 0)            return;        this.footerLayoutID = footLayoutID;        isHasFooter = true;    }    @Override    public int getItemViewType(int position) {        int viewType = TYPE_ITEM;        if (isHasHeader) {            if (isHeaderPosition(position)) {                viewType = TYPE_HEADER;            }        }        if (isHasFooter) {            if (isFooterPosition(position)) {                viewType = TYPE_FOOTER;            }        }        return viewType;    }    protected boolean isFooterPosition(int position) {        return position == getItemCount() - 1 ? true : false;    }    protected boolean isHeaderPosition(int position) {        return position == 0 ? true : false;    }    @Override    public int getItemCount() {        int count = mLists == null ? 0 : mLists.size();        if (isHasFooter) {            count++;        }        if (isHasHeader) {            count++;        }        return count;    }}

好了,这样我们通用的recyclerview的adapter就写好了。但是这样有个问题,如果我要想加载不同的布局,那怎么实现呢,显然BaseAdapter是不够用的,给大家一个思路, 如果要加载不同的布局,显然需要多个LayoutID和多个ViewType,既然他们都是int类型, 那完全可以把LayoutID作为adapter的ViewType来实现,然后在oncreateView的时候需要压入的layout直接拿viewType来使用就可以了。该思路实现的具体代码在 https://github.com/jiang111/SuperRecyclerViewAdapter

欢迎star和fork

0 0