[置顶] 超级简单RecycleViewAdapter的封装-支持多视图,多点击回调
2016-08-09 18:22
429 查看
其实RecycleView已经出来很长时间了,对RecycleView的用法网上也有很多教程了。本篇文章不讲解RecycleView的用法,不讲解LayoutManager的用法也不讲解ItemDecoration的用法,我们只关注Adapter的用法以及如何封装成一个通用的Adapter
通过以上代码演示,我们可以得出结论:构造一个比较完整的Adapter至少需要完成以下三件事情
1.
2.
3. 新建ViewHolder类来存储Item视图及其子视图
如果需要实现点击事件,需要在onBindViewHolder中适当绑定点击事件,比如在以上代码中绑定了点击列表视图中的Item根视图的点击事件如下:
在需要实现具体的点击事件时调用如下代码:
比如以上代码中处理了点击Item跟视图的点击事件,如果需要点击根视图中的icon子视图如何实现?
是不是继续写setOnXXXListener,麻烦也不太现实
如果要实现列表中多视图展示如何实现?正常如果需要支持多视图咱们是在
以上方案纯属针对某种列表来实现的,如果换了一个列表视图咱们就需要重现创建adapter并分别在
使用方法如下:
单视图方式:
定义adapter
在需要时使用:
可以看出我们轻松的实现了同一Item视图不同子视图的点击监听,并且在MainAdapter子类中只需通过getLayoutId告诉父类Item视图对应的视图id,并在convert方法中只更新视图即可
如果需要支持多视图模式则只需在子类中重现getViewType即可,代码如下:
完整的代码及案例可以到我的github下载
demo开源github地址如下:
LGRecycleViewAdapter
欢迎大家访问并star,如果有任何问题可以在评论中加以提问,谢谢~~
Adapter的正常使用方法
其实很简单,只需要继承RecyclerView.Adapter传入范型类型为ViewHolder的子类就可以,代码演示如下:MainActivity.java
public class MainActivity extends AppCompatActivity { ... @Override protected void onCreate(Bundle savedInstanceState) { ... List<String> datas = new ArrayList<>(); for (int i = 0; i < 20; ++i) { datas.add("item:" + (i + 1)); } layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); MyAdapter myAdapter = new MyAdapter(datas); myAdapter.setItemClickListener(new MyAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"root clicked..." + position); } }); recyclerView.setAdapter(myAdapter); } private static class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{ private List<String> dataList; private ItemClickListener itemClickListener; public MyAdapter(List<String> dataList){ this.dataList = dataList; } public interface ItemClickListener { void onItemClicked(View view,int position); } //设置点击回调接口 public void setItemClickListener(ItemClickListener itemClickListener) { this.itemClickListener = itemClickListener; } //生成ViewHolder @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_view_main1, parent, false); return new ViewHolder(itemView); } private String getItem(int position){ return dataList.get(position); } //更新列表Item视图(根据需要绑定click事件) @Override public void onBindViewHolder(ViewHolder holder, final int position) { String str = getItem(position); // holder.icon.setImageDrawable(xxx); holder.name.setText(str); holder.root.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(itemClickListener != null) itemClickListener.onItemClicked(v,position); } }); } @Override public int getItemCount() { return dataList.size(); } //ViewHolder保存每个item视图 public class ViewHolder extends RecyclerView.ViewHolder{ private ImageView icon; private TextView name; private View root; public ViewHolder(View itemView) { super(itemView); icon = (ImageView)itemView.findViewById(R.id.icon); name = (TextView)itemView.findViewById(R.id.id_text); root = itemView.findViewById(R.id.root); } } } }
通过以上代码演示,我们可以得出结论:构造一个比较完整的Adapter至少需要完成以下三件事情
1.
onCreateViewHolder通过视图Id加载不同Item视图并生成ViewHolder用来保存每个列表Item视图
2.
onBindViewHolder更新列表Item视图(填充model数据)
3. 新建ViewHolder类来存储Item视图及其子视图
如果需要实现点击事件,需要在onBindViewHolder中适当绑定点击事件,比如在以上代码中绑定了点击列表视图中的Item根视图的点击事件如下:
holder.root.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(itemClickListener != null) itemClickListener.onItemClicked(v,position); } });
在需要实现具体的点击事件时调用如下代码:
myAdapter.setItemClickListener(new MyAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"root clicked..." + position); } });
问题
如果需要实现在同一个Item视图中点击不同view要实现不同功能比如以上代码中处理了点击Item跟视图的点击事件,如果需要点击根视图中的icon子视图如何实现?
是不是继续写setOnXXXListener,麻烦也不太现实
如果要实现列表中多视图展示如何实现?正常如果需要支持多视图咱们是在
onCreateViewHolder方法中根据不同的ViewType来加载不同的Item视图代码演示如下:
//重写getItemViewType函数,更具需要返回不同的viewType @Override public int getItemViewType(int position) { String model = getItem(); if(...){ return 1; }else if(...){ return 2; } return super.getItemViewType(position); } //生成ViewHolder @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { int itemViewId = -1; if(viewType == 1){ itemViewId = R.layout.item_view_main1; }else if(viewType == 2){ itemViewId = R.layout.item_view_main2; } View itemView = LayoutInflater.from(parent.getContext()).inflate(itemViewId, parent, false); return new ViewHolder(itemView); }
以上方案纯属针对某种列表来实现的,如果换了一个列表视图咱们就需要重现创建adapter并分别在
onCreateViewHolder,
onBindViewHolder方法中实现不同逻辑并重新创建xxxViewHolder继承ViewHolder来保存不同的Item视图
解决方案
基于以上问题,给出如下方案LGViewHolder.java用来设计通用的ViewHolder
public class LGViewHolder extends RecyclerView.ViewHolder { private SparseArray<View> mViews; private View mConvertView;//缓存itemView内部的子View public LGViewHolder(View itemView) { super(itemView); mConvertView = itemView; mViews = new SparseArray<>(); } /** * 加载layoutId视图并用LGViewHolder保存 * @param parent * @param layoutId * @return */ protected static LGViewHolder getViewHolder(ViewGroup parent, int layoutId) { View itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false); return new LGViewHolder(itemView); } /** * 根据ItemView的id获取子视图View * @param viewId * @return */ public View getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); mViews.put(viewId, view); } return view; } }
LGRecycleViewAdapter.java
public abstract class LGRecycleViewAdapter<T> extends RecyclerView.Adapter<LGViewHolder> { private final String TAG = "LGRecycleViewAdapter"; //存储监听回调 private SparseArray<ItemClickListener> onClickListeners; private List<T> dataList; public interface ItemClickListener { void onItemClicked(View view,int position); } public LGRecycleViewAdapter(List<T> dataList) { this.dataList = dataList; onClickListeners = new SparseArray<>(); } /** * 存储viewId对应的回调监听实例listener * @param viewId * @param listener */ public void setOnItemClickListener(int viewId,ItemClickListener listener) { ItemClickListener listener_ = onClickListeners.get(viewId); if(listener_ == null){ onClickListeners.put(viewId,listener); } } /** * 获取列表控件的视图id(由子类负责完成) * @param viewType * @return */ public abstract int getLayoutId(int viewType); //更新itemView视图(由子类负责完成) public abstract void convert(LGViewHolder holder, T t, int position); public T getItem(final int position){ if(dataList == null) return null; return dataList.get(position); } @Override public LGViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { int layoutId = getLayoutId(viewType); LGViewHolder viewHolder = LGViewHolder.getViewHolder(parent, layoutId); return viewHolder; } @Override public void onBindViewHolder(LGViewHolder holder, final int position) { T itemModel = dataList.get(position); convert(holder, itemModel, position);//更新itemView视图 //设置点击监听 for (int i = 0; i < onClickListeners.size(); ++i){ int id = onClickListeners.keyAt(i); View view = holder.getView(id); if(view == null) continue; final ItemClickListener listener = onClickListeners.get(id); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(listener != null){ listener.onItemClicked(v,position); } } }); } } @Override public int getItemCount() { if (dataList == null) return 0; return dataList.size(); } public void destroyAdapter(){ if(onClickListeners != null) onClickListeners.clear(); onClickListeners = null; if(dataList != null) dataList.clear(); dataList = null; } }
使用方法如下:
单视图方式:
定义adapter
private static class MainAdapter extends LGRecycleViewAdapter<String> { ... @Override public int getLayoutId(int viewType) { return R.layout.item_view_main1; } @Override public void convert(LGViewHolder holder, String s, final int position) { TextView textView = (TextView) holder.getView(R.id.id_text); textView.setText(s); } }
在需要时使用:
mainAdapter = new MainAdapter(datas); mainAdapter.setOnItemClickListener(R.id.root, new LGRecycleViewAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"root clicked..." + position); } }); mainAdapter.setOnItemClickListener(R.id.icon, new LGRecycleViewAdapter.ItemClickListener() { @Override public void onItemClicked(View view, int position) { Log.d(TAG,"icon clicked..." + position); } }); recyclerView.setAdapter(mainAdapter);
可以看出我们轻松的实现了同一Item视图不同子视图的点击监听,并且在MainAdapter子类中只需通过getLayoutId告诉父类Item视图对应的视图id,并在convert方法中只更新视图即可
如果需要支持多视图模式则只需在子类中重现getViewType即可,代码如下:
MainAdapter.java
@Override public int getLayoutId(int viewType) { if(viewType == 1) return R.layout.item_view_main1; return R.layout.item_view_main2; } //支持不同viewType视图 @Override public int getItemViewType(int position) { String model = getItem(position);//实际开发中可以通过model的属性来决定返回viewType类型 if(position % 2 == 0) return 1; return 2; }
写在最后
为了简单起见,本篇文章设计的adapter适合没有header和footer视图的RecycleView,至于这方面的功能打算在github上更新完整的代码及案例可以到我的github下载
demo开源github地址如下:
LGRecycleViewAdapter
欢迎大家访问并star,如果有任何问题可以在评论中加以提问,谢谢~~
相关文章推荐
- 超级简单RecycleViewAdapter的封装-支持多视图,多点击回调
- 超级简单RecycleViewAdapter的封装-支持多视图,多点击回调
- android RecycleView Adapter简单封装
- 简单封装PagerAdapter以支持多种类型的视图
- android RecycleView Adapter简单封装
- android RecycleView Adapter简单封装
- 简单的封装BaseRecycleviewAdapter
- RecycleView设置点击的两种方式:adapter中的onBindViewHolder(VH,int)方法中进行;实现RecyclerView的addonItemTouchListerner()
- RecyclerView.Adapter 的简单封装
- RecycleView + SwipeRefreshLayout 对adapter和刷新的封装
- RecyclerView.Adapter封装,包括点击监听,长按监听,继承时不需要重新设置
- [置顶] RecycleView的基本配置和使用方法(四)---RecycleView实现简单demo
- 用recycleView封装成可扩展列表 点击父布局时报数组越界错误
- 超级好用的仿recycleview的listview适配器与viewholder封装
- BaseRecycleViewAdapter的封装,基于多种bean数据源的呈现
- RecycleView(BaseViewHolder+BaseAdapter+不同类型适配+点击事件)
- RecyclerView Adapter简单封装
- 简单的 TouchID demo 的使用 && UIlaterView block的封装 && UIAlertController使用.block的回调
- Android-万能 Adapter 封装(实现textview,imageView 的简单封装,封装 jar 包)
- android:RecycleView的简单封装使用