打造通用的 Adapter,是为了避免 在有多个 RecycleView 的情况下,需要创建对应个数的 Adapter 类,每个类都要去写 onCreateViewHolder 等大量的重复性的代码。
通用的 ViewHolder
RecyclerView要求必须使用ViewHolder模式,一般我们在使用过程中,都需要去建立一个新的ViewHolder然后作为泛型传入Adapter。那么想要建立通用的Adapter,必须有个通用的ViewHolder。
首先我们确定下ViewHolder的主要的作用,实际上是通过成员变量存储对应的convertView中需要操作的字View,避免每次findViewById,从而提升运行的效率。
那么既然是通用的View,那么对于不同的ItemType肯定没有办法确定创建哪些成员变量View,取而代之的只能是个集合来存储了。
那么代码如下:
/**
* Created by zhangyb on 2017/7/3.
*/
public class ViewHolder extends RecyclerView.ViewHolder {
private SparseArray<View> mViews;
private View mConvertView;
private Context mContext;
public ViewHolder(Context context, View itemView) {
super(itemView);
mContext = context;
mConvertView = itemView;
mViews = new SparseArray<View>();
}
public static ViewHolder createViewHolder(Context context, View itemView) {
return new ViewHolder(context, itemView);
}
public static ViewHolder createViewHolder(Context context, ViewGroup parent, int layoutId) {
View itemView = LayoutInflater.from(context).inflate(layoutId, parent, false);
return new ViewHolder(context, itemView);
}
/**
* 通过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 View getConvertView() {
return mConvertView;
}
/****以下为辅助方法*****/
/**
* 设置TextView的值
*
* @param viewId
* @param text
* @return
*/
public ViewHolder setText(int viewId, String text) {
TextView tv = getView(viewId);
tv.setText(text);
return this;
}
public ViewHolder setImageResource(int viewId, int resId) {
ImageView view = getView(viewId);
view.setImageResource(resId);
return this;
}
public ViewHolder setImageBitmap(int viewId, Bitmap bitmap) {
ImageView view = getView(viewId);
view.setImageBitmap(bitmap);
return this;
}
public ViewHolder setImageDrawable(int viewId, Drawable drawable) {
ImageView view = getView(viewId);
view.setImageDrawable(drawable);
return this;
}
public ViewHolder setBackgroundColor(int viewId, int color) {
View view = getView(viewId);
view.setBackgroundColor(color);
return this;
}
public ViewHolder setBackgroundRes(int viewId, int backgroundRes) {
View view = getView(viewId);
view.setBackgroundResource(backgroundRes);
return this;
}
public ViewHolder setTextColor(int viewId, int textColor) {
TextView view = getView(viewId);
view.setTextColor(textColor);
return this;
}
public ViewHolder setTextColorRes(int viewId, int textColorRes) {
TextView view = getView(viewId);
view.setTextColor(mContext.getResources().getColor(textColorRes));
return this;
}
/**
* 关于事件的
*/
public ViewHolder setOnClickListener(int viewId, View.OnClickListener listener) {
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
public ViewHolder setOnClickListener(View view, View.OnClickListener listener) {
view.setOnClickListener(listener);
return this;
}
public ViewHolder setOnTouchListener(int viewId, View.OnTouchListener listener) {
View view = getView(viewId);
view.setOnTouchListener(listener);
return this;
}
public ViewHolder setOnLongClickListener(int viewId, View.OnLongClickListener listener) {
View view = getView(viewId);
view.setOnLongClickListener(listener);
return this;
}
}
我们的ViewHolder继承自RecyclerView.ViewHolder,内部通过SparseArray来缓存我们itemView内部的子View,从而得到一个通用的ViewHolder。每次需要创建ViewHolder只需要传入我们的layoutId即可。
封装 Adapter
public abstract class CommonAdapter<T> extends RecyclerView.Adapter<ViewHolder> {
protected Context mContext;
protected int mLayoutId;
protected List<T> mDatas;
public CommonAdapter(Context context, int layoutId, List<T> datas) {
mContext = context;
mLayoutId = layoutId;
mDatas = datas;
}
@Override
public ViewHolder onCreateViewHolder(final ViewGroup parent, int viewType) {
return ViewHolder.createViewHolder(mContext, parent, mLayoutId);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
convert(holder, mDatas.get(position));
}
public abstract void convert(ViewHolder holder, T t);
@Override
public int getItemCount() {
return mDatas.size();
}
}
onBindViewHolder这里主要用于数据、事件绑定,我们这里直接抽象出去,让用户去操作。使用起来是这样的:
//使用 CommonAdapter,传入 layout id 和data,好吃是不需要自己创建一个Adapter类 和 ViewHolder,不需复写 onCreateViewHolder等大量重复代码
recyclerView.setAdapter(new CommonAdapter<String>(this, R.layout.item_picture_up, dataList) {
@Override
public void convert(ViewHolder holder, final String data) {
holder.setText(R.id.text, data);
//方便的添加监听事件
holder.setOnClickListener(holder.itemView, new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "data : " + data, Toast.LENGTH_SHORT).show();
}
});
}
});
多种ItemViewType(不同 layout 的 item)
多种ItemViewType,一般我们的写法是:
- 复写getItemViewType,根据我们的bean去返回不同的类型
- onCreateViewHolder中根据itemView去生成不同的ViewHolder
如果大家还记得,我们的ViewHolder是通用的,唯一依赖的就是个layoutId。那么上述第二条就变成,根据不同的itemView告诉我用哪个layoutId即可,生成viewholder这种事我们通用adapter来做。
于是,引入一个接口:
public interface MultiItemTypeSupport<T> {
int getLayoutId(int itemType);
int getItemViewType(int position, T t);
}
可以很清楚的看到,这个接口实际就是完成我们上述的两条工作。用户在使用过程中,通过实现上面两个方法,指明不同的Bean返回什么itemViewType,不同的itemView所对应的layoutId.
ok,有了上面这个接口,我们的参数就够了,下面开始我们的MultiItemCommonAdapter的编写。
public abstract class MultiItemCommonAdapter<T> extends CommonAdapter<T> {
protected MultiItemTypeSupport<T> mMultiItemTypeSupport;
public MultiItemCommonAdapter(Context context, List<T> datas, MultiItemTypeSupport<T> multiItemTypeSupport) {
super(context, -1, datas);
mMultiItemTypeSupport = multiItemTypeSupport;
}
@Override
public int getItemViewType(int position) {
return mMultiItemTypeSupport.getItemViewType(position, mDatas.get(position));
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layoutId = mMultiItemTypeSupport.getLayoutId(viewType);
return ViewHolder.createViewHolder(mContext, parent, layoutId);
}
}
很简单,不再说明。
使用:
//使用 MultiItemCommonAdapter,回调 getItemViewType,让用户传入不同的 viewType,并根据 viewType 在 getLayoutId 中传入 layout id
recyclerView.setAdapter(new MultiItemCommonAdapter<String>(this, dataList, new MultiItemTypeSupport<String>() {
@Override
public int getLayoutId(int viewType) {
//根据不同 viewType 返回不同的 layout 给 viewHolder类 拿去创建 ViewHolder。
if (viewType == 0) {
return R.layout.item_picture_left;
}
return R.layout.item_picture_up;
}
@Override
public int getItemViewType(int position, String s) {
//前三行的 item 和 后面的 item 使用不同的 item
if (position < 3) {
return 0;
}
return 1;
}
}) {
@Override
public void convert(ViewHolder holder, String data) {
holder.setText(R.id.text, data);
}
});
参考
一些想法
RecyclerView 写了四篇文章,其实还是有很多东西,没再写了,因为真的快写吐了。。。很多东西 都是越了解就感觉越了解的不够,想要成为 Android 高手 还有很长的路要走…… 每天坚持学些东西,日积月累总会质变的,加油。
ps:发现了一个很不错的Android导航网站:AndroidCat安卓书签网,是专门为Android开发者而收集整理的网站资源导航,以后可以方便的通过这个门户找资源啦!
网友评论