提炼RecyclerView、ListView的通用适配器,大幅减少项目中adapter的代码量

来源:互联网 发布:淘宝网9.9元包邮 编辑:程序博客网 时间:2024/06/09 19:38

项目实际开发过程中发现几乎每个页面都要使用到adapter,如果只是单纯的提取出一个父类BaseAdapter的话,那我们需要创建的adapter文件会很多。

所以看来是有必要封装出通用的适配器才能让自己更轻松的敲代码:


1.RecyclerView


首先看一下适用于RecyclerView的通用viewHolder:

/** * Created by Dovar on 2016/12/28 0028. * Email:xiaohe0949@163.com * 通用RecyclerView的ViewHolder */public class RCommenViewHolder extends RecyclerView.ViewHolder {    private SparseArray<View> mViews;    private View mConvertView;    public RCommenViewHolder(View itemView) {        super(itemView);        mConvertView = itemView;        mViews = new SparseArray<View>();    }    /**     * 通过viewId获取控件     *     * @param viewId     * @return     */    public <T extends View> T getView(int viewId) {        View view = mViews.get(viewId);        if (view == null) {            view = mConvertView.findViewById(viewId);            mViews.put(viewId, view);        }        return (T) view;    }    public RCommenViewHolder setText(int viewId, String text) {        TextView tv = getView(viewId);        tv.setText(text);        return this;    }    public RCommenViewHolder setImageResource(int viewId, int resId) {        ImageView view = getView(viewId);        view.setImageResource(resId);        return this;    }    /**     * 使用glide加载网络图片     */    public void setImageUrl(Context context, int id, String url) {        ImageView iv = getView(id);        if (iv != null && url != null) {            Glide.with(context).load(url).error(R.mipmap.ic_launcher).into(iv);        }    }    /**     * 给itemView中的子View添加点击事件     */    public RCommenViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {        View view = getView(viewId);        view.setOnClickListener(listener);        return this;    }}
接下来就是我们常用到的适配器,可增加headerView、footerView
/** * Created by Dovar on 2016/12/28 0028. * Email:xiaohe0949@163.com * 通用RecyclerView适配器 * 本类只适用于三种布局类型:TYPE_HEADER、TYPE_FOOTER、TYPE_COMMON * 多布局类型请使用{@link MultiCommonAdapter} */public abstract class RCommenAdapter<T> extends RecyclerView.Adapter<RCommenViewHolder> {    private static final String TAG = "adapter";    protected Context mContext;    private int mLayoutId;    protected List<T> mDatas;    private static final int TYPE_COMMON = 0;    private static final int TYPE_FOOTER = 1;    private static final int TYPE_HEADER = 2;    private boolean hasFooter = false;//是否已添加尾布局    private boolean hasHeader = false;//是否已添加头布局    private View headerView;    private View footerView;    /**     * 添加尾布局     *     * @param footerView     */    public void addFooterView(View footerView) {        this.footerView = footerView;        hasFooter = true;    }    /**     * 添加头布局     *     * @param headerView     */    public void addHeaderView(View headerView) {        this.headerView = headerView;        hasHeader = true;    }    /**     * 添加一条数据     *     * @param data     * @param isNotify 是否需要在添加数据后立即刷新界面     */    public void addData(T data, boolean isNotify) {        if (data != null) {            Log.d(TAG, "addData: " + data);            mDatas.add(data);            if (isNotify) {                notifyDataSetChanged();//可修改为局部刷新            }        } else {            Log.d(TAG, "addData: data==null");        }    }    /**     * 添加数据集合     *     * @param datas   数据list     * @param isClear 是否需要先清空原有数据再添加     */    public void addDatas(List<T> datas, boolean isClear) {        if (isClear) {            this.mDatas.clear();        }        if (datas != null) {            this.mDatas.addAll(datas);        } else {            Log.d(TAG, "addDatas: datas==null");        }        notifyDataSetChanged();    }    /**     * 添加数据数组     *     * @param datas   数据collection     * @param isClear 是否需要先清空原有数据再添加     */    public void addDatas(T[] datas, boolean isClear) {        if (isClear) {            this.mDatas.clear();        }        if (datas != null) {            Collections.addAll(this.mDatas, datas);        } else {            Log.d(TAG, "addDatas: datas==null");        }        notifyDataSetChanged();    }    /**     * 获取mDatas中对应下标的item     *     * @param pos     */    public T getItem(int pos) {        if (pos >= 0 && pos < mDatas.size()) {            return mDatas.get(pos);        }        Log.d(TAG, "getItem: getItem==null");        return null;    }    /**     * 获取mDatas     *     * @return     */    public List<T> getDatas() {        return mDatas;    }    /**     * 返回所有item数量,包括header、footer     * 此方法的返回值直接决定recyclerView的child数量     *     * @return     */    @Override    public int getItemCount() {        //header与footer都有        if (hasFooter && hasHeader) return getDataCount() + 2;        //header与footer都没有        if (!hasFooter && !hasHeader) return getDataCount();        //header与footer只有一个        return getDataCount() + 1;    }    /**     * 返回bodyItem数量     * mDatas.size()     *     * @return     */    private int getDataCount() {        if (mDatas.size() == 0) {            Log.d(TAG, "getItemCount: count==0");        }        return mDatas.size();    }    /**     * 清空数据源     */    public void clear() {        if (mDatas != null) {            mDatas.clear();        } else {            Log.d(TAG, "clear: mDatas==null");        }    }    /**     * 移除指定mDatas对应position上的数据     *     * @param position     */    public void remove(int position) {        if (position >= 0 && position < mDatas.size()) {            mDatas.remove(position);            notifyItemRemoved(position);        }    }    public abstract void convert(RCommenViewHolder vh, int position);    public RCommenAdapter(Context context, int layoutId, List<T> datas) {        mContext = context;        mLayoutId = layoutId;        mDatas = datas;    }    @Override    public RCommenViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        if (viewType == TYPE_HEADER) {            if (headerView == null) {                return null;            }            return new RCommenViewHolder(headerView);        }        if (viewType == TYPE_FOOTER) {            if (footerView == null) {                return null;            }            return new RCommenViewHolder(footerView);        }        return new RCommenViewHolder(View.inflate(mContext, mLayoutId, null));    }    @Override    public void onBindViewHolder(RCommenViewHolder holder, int position) {        if (getItemViewType(position) == TYPE_HEADER) return;        if (getItemViewType(position) == TYPE_FOOTER) return;        if (hasHeader) {//有header时,header对应的position为0,其他从1开始            convert(holder, position - 1);        } else {            convert(holder, position);        }    }    @Override    public int getItemViewType(int position) {        if (headerView != null && hasHeader && position == 0) return TYPE_HEADER;        if (footerView != null && hasFooter && position == getItemCount() - 1) return TYPE_FOOTER;        return TYPE_COMMON;    }    /**     * GridManager时设置header、footer跨列     *     * @param recyclerView     */    @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) {                    switch (getItemViewType(position)) {                        case TYPE_FOOTER:                        case TYPE_HEADER:                            //设置跨列                            return gridManager.getSpanCount();                        default:                            return 1;                    }                }            });        }    }}

上面这是适用于RecyclerView中只有一种布局的情况,接下来就是适用于多种布局的通用适配器了:
/** * Created by Dovar on 2016/12/28 0028. * Email:xiaohe0949@163.com * 通用RecyclerView多布局适配器 *  */public abstract class MultiCommonAdapter<T> extends RCommenAdapter<T> {    public MultiCommonAdapter(Context context, List<T> datas) {        super(context, -1, datas);    }    @Override    public int getItemViewType(int position) {        return getItemType(position);    }    public abstract int getItemType(int position);    //利用viewType返回layoutId,直接生成viewHolder    @Override    public RCommenViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {        return new RCommenViewHolder(View.inflate(mContext, viewType, null));    }    @Override    public void onBindViewHolder(RCommenViewHolder holder, int position) {        convert(holder, position);    }}

2.ListView
首先是ListView的通用viewHolder:
/** * listView 通用ViewHolder * 与CommenAdapter结合使用 * Created by Dovar on 2016/11/22 0022. */public class CommenViewHolder {    private View convertView;    private SparseArray<View> views;//储存子view,复用,省去重复的findViewById    public CommenViewHolder(View convertView) {        this.convertView = convertView;        this.views = new SparseArray<>();    }    public static CommenViewHolder get(View convertView, Context mContext, int resouce) {        CommenViewHolder vh;        if (convertView == null) {            convertView = View.inflate(mContext, resouce, null);            vh = new CommenViewHolder(convertView);            convertView.setTag(vh);        } else {            vh = (CommenViewHolder) convertView.getTag();        }        return vh;    }    public View getConvertView() {        return convertView;    }    public <T extends View> T getView(int id) {        View view = views.get(id);        if (view == null) {            view = convertView.findViewById(id);            views.put(id, view);        }        return (T) view;    }    public void setText(int id, String text) {        TextView tv = getView(id);        if (tv != null)            tv.setText(text);    }    public void setImageResource(int id, int drawableId) {        ImageView iv = getView(id);        if (iv != null)            iv.setImageResource(drawableId);    }    /**     * 使用glide加载网络图片     */    public void setImageUrl(Context context, int id, String url) {        ImageView iv = getView(id);        if (iv != null && url != null) {            Glide.with(context).load(url).error(com.youmasc.youma.R.mipmap.ic_launcher).into(iv);        }    }    public void setOnClickListener(int viewId, View.OnClickListener listener) {        View view = getView(viewId);        view.setOnClickListener(listener);    }}

然后,就是ListView的万能适配器了:
/** * ListView通用adapter * 与CommenViewHolder结合使用 * Created by Dovar on 2016/11/22 0022. */public abstract class CommenAdapter<T> extends BaseAdapter {    protected List<T> mList;    protected Context mContext;    protected int mResouce;    protected final String TAG = "tag";    public CommenAdapter(List<T> mList, Context mContext, int mResouce) {        this.mList = mList;        this.mContext = mContext;        this.mResouce = mResouce;    }    public void addDatas(List<T> list, boolean isClear) {        if (isClear) {            mList.clear();        }        if (list != null) {            mList.addAll(list);        }        notifyDataSetChanged();    }    public void addDatas(T[] array) {        mList.clear();        if (array != null) {            Collections.addAll(mList, array);            notifyDataSetChanged();        }    }    public void addData(T clazz) {        if (clazz != null) {            mList.add(clazz);        }    }    public void remove(T clazz){        mList.remove(clazz);    }    public void replace(int position, T data) {        if (position < getCount()) {            mList.remove(position);            mList.add(position, data);            notifyDataSetChanged();        }    }    public List<T> getList() {        return mList;    }    public void clear() {        mList.clear();    }    @Override    public int getCount() {        return mList.size();    }    @Override    public T getItem(int position) {        return mList.get(position);    }    @Override    public long getItemId(int position) {        return position;    }    @Override    public View getView(int position, View convertView, ViewGroup parent) {        if (getCount() == 0) return null;        CommenViewHolder viewHolder = CommenViewHolder.get(convertView, mContext, mResouce);        convert(viewHolder, position);        return viewHolder.getConvertView();    }    public abstract void convert(CommenViewHolder vh, int position);}

好了,比较直接,基本都是直接贴代码,关键方法都注释上了,相信基本也都能看明白
如果还有哪里有疑问的或者发现代码有问题的,欢迎评论里讨论

0 0