您的位置:首页 > 其它

RecyclerView 的简单封装

2016-12-11 17:02 417 查看

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.
* 1273482124@qq.com
*/
public class ViewHolder extends RecyclerView.ViewHolder {
private Context mContext;
private SparseArray<View> 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 <T>
* @return
*/
public <T extends View> 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<T> mDatas;
protected LayoutInflater mInflater;
protected int mLayoutId;

public CommonAdapter(Context context,List<T> 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<T> 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<String> adapter = new CommonAdapter<String>() {
@Override
public void convert(ViewHolder holder, String s, int position) {
holder.setText(R.id.tv,"hello");
}
};


4 多种ItemType类型支持

在项目中,我们经常需要支持多种类型的Item的Adapter,例如今日头条的界面:



基本思想就是复写public int getItemViewType(int position),然后根据position处返回特定的type,然后在根据type类型返回响应的布局id,根据布局id生成响应的View,这样就可以实现如上图的效果了。

这里我们引入另外一个接口来支持多种类型的Item。

public interface MultiTypeItem<T> {
//根据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<T> mMultiItemType;

public MultiAdapter(Context context, List<T> datas, MultiTypeItem<T> 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实例即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: