偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder
Posted TellH
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder相关的知识,希望对你有一定的参考价值。
前言
昨天开始接触江湖口碑很好的RecyclerView,事实上,我已经被她的强大所征服了!资源回收,数据绑定,布局显示,分割线,Item动画多个模块高度解耦,灵活优雅。其实,RecyclerView在使用上已经是相当简单了(个人觉得),但仍有很多代码是可以加以封装的。今天受简书上一篇博文的启发,作为写代码喜欢优(tou)雅(lan)的人,想到了一种封装方式,打造万能适配器,供大家食用。
正统模式:
public class SimplerItemAdapter extends RecyclerView.Adapter<SimplerItemAdapter.SimpleItemViewHolder >
private List <String> items;
public SimplerItemAdapter (@NonNull List<String> dateItems )
this.items = (dateItems != null ? dateItems : new ArrayList<String>());
@Override public SimpleItemViewHolder onCreateViewHolder (ViewGroup viewGroup, int viewType)
View itemView = LayoutInflater.from( viewGroup.getContext ()).inflate(R.layout .item, viewGroup, false );
return new SimpleItemViewHolder(itemView);
@Override public void onBindViewHolder (SimpleItemViewHolder viewHolder, int position)
viewHolder.textView .setText(items.get (position));
@Override public int getItemCount ()
return (this.items != null) ? this .items. size() : 0 ;
protected final static class SimpleItemViewHolder extends RecyclerView.ViewHolder
protected TextView textView ;
public SimpleItemViewHolder (View itemView)
super(itemView);
this.textView = (TextView) itemView.findViewById (R. id.text);
- 首先,
@Override public int getItemCount ()
这段代码完全可以封装起来的。
return (this.items != null) ? this .items. size() : 0 ;
- onCreatedViewHolder()方法作用是绑定item视图,可以进一步封装,给子类提供一个getLayoutItemId的抽象方法,这样就可以简化成一行代码了。
- 因此我们发现,这个adapter的核心代码在与onBindViewHolder()中,作用是将数据跟视图(ViewHolder)绑定,可以给子类提供一个bindData()抽象方法。
- 当然了,使用泛型也是极好的,拓广了adapter的使用范围。
- 添加点击事件的监听也可以封装到万能adapter中,子类就不用再写item点击事件处理代码了
封装后的Adapter
public abstract class BaseRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerViewHolder>
protected final List<T> mData;
protected final Context mContext;
protected LayoutInflater mInflater;
private OnItemClickListener mClickListener;
private OnItemLongClickListener mLongClickListener;
public BaseRecyclerAdapter(Context ctx, List<T> list)
mData = (list != null) ? list : new ArrayList<T>();
mContext = ctx;
mInflater = LayoutInflater.from(ctx);
@Override
public RecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
final RecyclerViewHolder holder = new RecyclerViewHolder(mContext,
mInflater.inflate(getItemLayoutId(viewType), parent, false));
if (mClickListener != null)
holder.itemView.setOnClickListener(new View.OnClickListener()
@Override
public void onClick(View v)
mClickListener.onItemClick(holder.itemView, holder.getLayoutPosition());
);
if (mLongClickListener != null)
holder.itemView.setOnLongClickListener(new View.OnLongClickListener()
@Override
public boolean onLongClick(View v)
mLongClickListener.onItemLongClick(holder.itemView, holder.getLayoutPosition());
return true;
);
return holder;
@Override
public void onBindViewHolder(RecyclerViewHolder holder, int position)
bindData(holder, position, mData.get(position));
@Override
public int getItemCount()
return mData.size();
public void add(int pos, T item)
mData.add(pos, item);
notifyItemInserted(pos);
public void delete(int pos)
mData.remove(pos);
notifyItemRemoved(pos);
public void setOnItemClickListener(OnItemClickListener listener)
mClickListener = listener;
public void setOnItemLongClickListener(OnItemLongClickListener listener)
mLongClickListener = listener;
abstract public int getItemLayoutId(int viewType);
abstract public void bindData(RecyclerViewHolder holder, int position, T item);
public interface OnItemClickListener
public void onItemClick(View itemView, int pos);
public interface OnItemLongClickListener
public void onItemLongClick(View itemView, int pos);
Super ViewHolder!
其实,这还没完呢!重头戏在ViewHolder上!RecyclerView强制我们使用ViewHolder模式,然而缺不可避免地要写findViewById代码,有没有办法不写这样的代码呢?甚至连ViewHolder都不写呢?当然可以!
public class RecyclerViewHolder extends RecyclerView.ViewHolder
private SparseArray<View> mViews;//集合类,layout里包含的View,以view的id作为key,value是view对象
private Context mContext;//上下文对象
public RecyclerViewHolder(Context ctx, View itemView)
super(itemView);
mContext = ctx;
mViews = new SparseArray<View>();
private <T extends View> T findViewById(int viewId)
View view = mViews.get(viewId);
if (view == null)
view = itemView.findViewById(viewId);
mViews.put(viewId, view);
return (T) view;
public View getView(int viewId)
return findViewById(viewId);
public TextView getTextView(int viewId)
return (TextView) getView(viewId);
public Button getButton(int viewId)
return (Button) getView(viewId);
public ImageView getImageView(int viewId)
return (ImageView) getView(viewId);
public ImageButton getImageButton(int viewId)
return (ImageButton) getView(viewId);
public EditText getEditText(int viewId)
return (EditText) getView(viewId);
public RecyclerViewHolder setText(int viewId, String value)
TextView view = findViewById(viewId);
view.setText(value);
return this;
public RecyclerViewHolder setBackground(int viewId, int resId)
View view = findViewById(viewId);
view.setBackgroundResource(resId);
return this;
public RecyclerViewHolder setClickListener(int viewId, View.OnClickListener listener)
View view = findViewById(viewId);
view.setOnClickListener(listener);
return this;
该类的核心方法是private T findViewById(int viewId),核心成员变量是private SparseArray mViews; 不信可以不写一句ViewHolder代码?接下来看看用法。
实践用法
添加Adapter仅需短短的几行代码:
Adapter = new BaseRecyclerAdapter<String>(this,mDataList)
@Override
public int getItemLayoutId(int viewType)
return R.layout.item;
@Override
public void bindData(RecyclerViewHolder holder, int position,String item)
//调用holder.getView(),getXXX()方法根据id得到控件实例,进行数据绑定即可
holder.setText(R.id.tv_num,item)
.getTextView(R.id.tv_title,item).setText(item);
;
完整代码:
private void init()
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mDataList = new ArrayList<>();
for (int i = 0; i <= 100; i++)
mDataList.add(String.valueOf(i));
//设置item动画
recyclerView.setItemAnimator(new DefaultItemAnimator());
mAdapter = new BaseRecyclerAdapter<String>(this,mDataList)
@Override
public int getItemLayoutId(int viewType)
return R.layout.item;
@Override
public void bindData(RecyclerViewHolder holder, int position,String item)
//调用holder.getView(),getXXX()方法根据id得到控件实例,进行数据绑定即可
holder.setText(R.id.tv_num,item)
.getTextView(R.id.tv_title,item).setText(item);
;
recyclerView.setAdapter(mAdapter);
//添加item点击事件监听
((BaseRecyclerAdapter)mAdapter).setOnItemClickListener(new BaseRecyclerAdapter.OnItemClickListener()
@Override
public void onItemClick(View itemView, int pos)
Toast.makeText(AdapterTestActivity.this, "click " + pos, Toast.LENGTH_SHORT).show();
);
((BaseRecyclerAdapter)mAdapter).setOnItemLongClickListener(new BaseRecyclerAdapter.OnItemLongClickListener()
@Override
public void onItemLongClick(View itemView, int pos)
Toast.makeText(AdapterTestActivity.this, "long click " + pos, Toast.LENGTH_SHORT).show();
);
//设置布局样式LayoutManager
recyclerView.setLayoutManager(new LinearLayoutManager(AdapterTestActivity.this, LinearLayoutManager.VERTICAL, false));
// recyclerView.addItemDecoration(new ItemDividerDecoration(MainActivity.this, OrientationHelper.VERTICAL));
如果觉得有什么不妥之处或建议,敬请指教!
完整项目代码已上传至Github。—Github跳转。
see also:
Listview的Adapter应该这样写
以上是关于偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder的主要内容,如果未能解决你的问题,请参考以下文章
让偷懒更彻底——用Butterknife 来为recyclerview 打造通用适配器(上)
为RecyclerView打造通用Adapter 让RecyclerView更加好用
ScratchView:一步步打造万能的 Android 刮奖效果控件