RecyclerView 的简单封装

1 前言

最近在学习Material Design设计,首当其冲就是学习RecyclerView,参考了下Hongyang自己对RecyclerView的ViewHolder与Adapter做了下简单的封装。下面,废话不多说,直接上干货。

2 ViewHolder的封装

ViewHolder在RecyclerView中的作用主要就是用来缓存我们每一个Item对应的View视图的,我们在Adapter中主要是在public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)回去创建一个ViewHolder,在 public void onBindViewHolder(ViewHolder holder, int position)会将holder与该position处的数据进行绑定(就是设置数据该怎么显示,这里需要访问ViewHolder中缓存的View)。基于此我们可以总结出ViewHolder的基本功能:

1 提供创建ViewHolder的功能

 这里主要包括两种,一种是直接传入一个View参数创建一个View,比如我们在ListView中经常使用的下面代码:
View view = LayoutInflater.from(mContext).inflate(R.layout.xxx,parent,false);
ViewHolder holder = new ViewHolder(view);
第二种就是直接传入一个layoutId,这一种我们在多种ItemType类型中经常会用到。

2 对ViewHolder中各种View的访问
一般ViewHolder中会有TextView,ImageView等,我们通过使用一个SparseArray来缓存我们加载过的View,我们经常需要对它设置文本内容,字体大小,图片内容等。

3 封装ViewHolder中各种View事件
一般主要是点击事件与长按事件,我这里只封装了点击事件

下面直接上封装好的ViewHolder

/**
 * Created by qiyei2015 on 2016/11/28.
 * [email protected]
 */
public class ViewHolder extends RecyclerView.ViewHolder {
    private Context mContext;
    private SparseArray mViews;//存储View,key 为int,value为View类型
    private View mConvertView;  //存储加载布局xml中的的所有View

    public ViewHolder(Context context,View view){
        super(view);
        mContext = context;
        mConvertView = view;
        mViews = new SparseArray<>();
    }

    /**
     * 创建ViewHolder,外部调用
     * @param context
     * @param view
     * @return
     */
    public static ViewHolder createViewHolder(Context context,View view){
        return new ViewHolder(context,view);
    }

    /**
     * 创建ViewHolder
     * @param context
     * @param parent
     * @param layoutId
     * @return
     */
    public static ViewHolder createViewHolder(Context context, ViewGroup parent,int layoutId){
        View itemView = LayoutInflater.from(context).inflate(layoutId,parent,false);
        return new ViewHolder(context,itemView);
    }

    /**
     * 根据id来查找View
     * @param viewId
     * @param 
     * @return
     */
    public  T getView(int viewId){
        View view = mViews.get(viewId);
        if (view == null){  //如果缓存里面没有,就从布局文件中查找
            view  = mConvertView.findViewById(viewId);  //从xml查找的,减少重复调用findViewById
            mViews.put(viewId,view);
        }
        return (T) view;
    }

    /**
     * 获取ConvertView
     * @return
     */
    public View getConvertView(){
        return mConvertView;
    }

    /**
     *  以下是设置TextView,imageView等View的一些常用方法
     * */

    /**
     * 设置Text
     * @param viewId
     * @param text
     * @return
     */
    public ViewHolder setText(int viewId,CharSequence text){
        TextView view = getView(viewId);
        view.setText(text);
        return this;
    }

    /**
     * 设置ImageView
     * @param viewId
     * @param resId
     * @return
     */
    public ViewHolder setImageResource(int viewId,int resId){
        ImageView view = getView(viewId);
        view.setImageResource(resId);
        return this;
    }

    /**
     * 设置ImageView的bitmap
     * @param viewId
     * @param bitmap
     * @return
     */
    public ViewHolder setImageBitmap(int viewId, Bitmap bitmap){
        ImageView view = getView(viewId);
        view.setImageBitmap(bitmap);
        return this;
    }

    /**
     * 设置View的点击事件
     * @param viewId
     * @param listener
     * @return
     */
    public ViewHolder setOnClickListener(int viewId,View.OnClickListener listener){
        View view = getView(viewId);
        view.setOnClickListener(listener);
        return this;
    }

}

这个就是我们封装好的ViewHolder,比较简单,使用起来还是比较方便的。使用静态方法创建对象。使用共有方法去设置对象,需要传入一个View的id值即可,可以根据项目的需要慢慢增加功能。

3 CommonAdapter的封装

CommonAdapter的封装就比较简单,主要是复写public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)和

public void onBindViewHolder(ViewHolder holder, int position)。其中有一个抽象的方法public abstract void convert(ViewHolder holder,T t,int position);这个主要是把holder与position处的数据做绑定的,这个需要子类来覆写,由子类来实现。

/**
 * Created by qiyei2015 on 2016/11/30.
 * 1273482124@qq.com
 */
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<ViewHolder> {

    protected Context mContext;
    protected List mDatas;
    protected LayoutInflater mInflater;
    protected int mLayoutId;

    public CommonAdapter(Context context,List list,int layoutId){
        mContext = context;
        mDatas = list;
        mInflater = LayoutInflater.from(mContext);
        mLayoutId = layoutId;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        ViewHolder holder = ViewHolder.createViewHolder(mContext,parent,mLayoutId);
        return holder;

    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        convert(holder,mDatas.get(position),position);
    }

    @Override
    public int getItemCount() {
        return mDatas.size();
    }

    /**
     * 设置数据
     * @param data
     */
    public void setData(List data){
        mDatas = data;
        notifyDataSetChanged();
    }

    /**
     * 根据position返回对应的数据
     * @param position
     * @return
     */
    public T getItem(int position){
        return mDatas.get(position);
    }


    /**
     * 子类实现的转换方法
     */
    public abstract void convert(ViewHolder holder,T t,int position);
}

这样子类只需要实现convert(ViewHolder holder,T t,int position)就可以了。比如:

        CommonAdapter adapter = new CommonAdapter() {
            @Override
            public void convert(ViewHolder holder, String s, int position) {
                holder.setText(R.id.tv,"hello");
            }
        };

4 多种ItemType类型支持

在项目中,我们经常需要支持多种类型的Item的Adapter,例如今日头条的界面:
RecyclerView 的简单封装_第1张图片
基本思想就是复写public int getItemViewType(int position),然后根据position处返回特定的type,然后在根据type类型返回响应的布局id,根据布局id生成响应的View,这样就可以实现如上图的效果了。
这里我们引入另外一个接口来支持多种类型的Item。

public interface MultiTypeItem {
    //根据itemType获取布局文件
    int getLayoutId(int itemType);
    //根据position及T 数据类型 返回对应的ItemType
    int getItemType(int position,T t);
}

支持多种ItemType的Adapter如下:

/**
 * Created by qiyei2015 on 2016/12/10.
 * 1273482124@qq.com
 */
public abstract class MultiAdapter<T> extends CommonAdapter<T> {

    protected MultiTypeItem mMultiItemType;

    public MultiAdapter(Context context, List datas, MultiTypeItem itemType){
        super(context,datas,-1);
        mMultiItemType = itemType;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        int id = mMultiItemType.getLayoutId(viewType);
        return ViewHolder.createViewHolder(mContext,parent,id);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        super.onBindViewHolder(holder, position);
    }

    /**
     * 返回position 对应的type
     * @param position
     * @return
     */
    @Override
    public int getItemViewType(int position) {
        return mMultiItemType.getItemType(position,getItem(position));
    }

}

使用也很简单,首先新建一个MultiTypeItem对象。然后新建MultiAdapter实例即可。

你可能感兴趣的:(android,应用开发)