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

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

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


1.RecyclerView


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

/**
 * Created by Dovar on 2016/12/28 0028.
 * Email:[email protected]
 * 通用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:[email protected]
 * 通用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:[email protected]
 * 通用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);
}

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

猜你喜欢

转载自blog.csdn.net/Dovar_66/article/details/54236178