完美解决RecyclerView点击事件、长按事件、子项点击事件
自从Google推出了RecyclerView之后,便可以完全取代ListView,个人感觉唯一的美中不足是对于itemView的各种点击事件不够完美。观点只代表个人看法。应最近项目需求实现itemView的子项点击事件,便写篇博客记录一下,若是能够帮到你,我深感荣幸。接下来,便对RecyclerView进行简单的封装,使得它更方便实现各种点击事件。
我们都知道,对与RecyclerView的使用,是创建一个adapter类,然后在adapter类中再创建一个ViewHolder的内部类。我们要做的,正是对这两个类进行封装,让其实现itemView点击事件、长按事件、子项点击事件。
首先,我的处理方式是,对于开发者来说,只需要对adapter进行setxxx()方法的调用,例如设置itemView的点击事件:adapter.setOnRecyclerViewItemClickListener(...);对该方法传入自定义的接口即可。也就是说,我们需要自定义一个adapter类。那我们就先创建一个类,命名为BaseRecylerAdapter,此后,我们也应当创建一个BaseViewHolder类,接下来开始搞事情。
BaseRecylerAdapter类
public abstract class BaseRecyclerAdapter extends RecyclerView.Adapter<BaseViewHolder> implements View.OnClickListener ,View.OnLongClickListener { private OnRecyclerViewItemClickListener onRecyclerViewItemClickListener; private OnRecyclerViewItemLongClickListener onRecyclerViewItemLongClickListener; private OnSubViewClickListener onSubViewClickListener; @Override public void onBindViewHolder(BaseViewHolder holder, int position) { holder.itemView.setTag(position); holder.onBind(position); if (onRecyclerViewItemClickListener != null) { holder.itemView.setOnClickListener(this); } if (onRecyclerViewItemLongClickListener != null) { holder.itemView.setOnClickListener(this); } if (onSubViewClickListener != null) { holder.setSubViewClickListener(onSubViewClickListener,position); } } public void setOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListener onRecyclerViewItemClickListener) { this.onRecyclerViewItemClickListener = onRecyclerViewItemClickListener; } public void setOnRecyclerViewItemLongClickListener(OnRecyclerViewItemLongClickListener onRecyclerViewItemLongClickListener) { this.onRecyclerViewItemLongClickListener = onRecyclerViewItemLongClickListener; } public void setOnSubViewClickListener(OnSubViewClickListener listener){ this.onSubViewClickListener = listener; } @Override public void onClick(View v) { if (v.getTag() != null) { int position = (int) v.getTag(); onRecyclerViewItemClickListener.onItemClick(position); } } @Override public boolean onLongClick(View v) { if (v.getTag() != null){ int position = (int)v.getTag(); onRecyclerViewItemLongClickListener.onItemLongClick(position); } return true; } public interface OnRecyclerViewItemClickListener { void onItemClick(int position); } public interface OnSubViewClickListener{ void onSubViewClick(View v, int position); } public interface OnRecyclerViewItemLongClickListener { void onItemLongClick(int position); } }
可以看到我们在类中创建了三个接口类
public interface OnRecyclerViewItemClickListener { void onItemClick(int position); } public interface OnSubViewClickListener{ void onSubViewClick(View v, int position); } public interface OnRecyclerViewItemLongClickListener { void onItemLongClick(int position); }
这三个接口便是用于点击事件的回调,看名字就能分别出各自的功能。itemView的点击回调public interface OnRecyclerViewItemClickListener,itemView的长按public interface OnRecyclerViewItemLongClickListener,子项View的点击回调public interface OnSubViewClickListener。都是点击事件的处理,没有点击发送怎么行呢,对吧!所以,这个类还实现了View.OnClickListener 和View.OnLongClickListener 这两个接口,本别实现itemView的点击事件和长按事件。
可以看到,BaseRecyclerAdapter继承自RecyclerView.Adapter<BaseViewHolder>,此时我们只需要实现onBindViewHolder 这个方法即可。来分析这个方法。
@Override public void onBindViewHolder(BaseViewHolder holder, int position) { holder.itemView.setTag(position); holder.onBind(position); if (onRecyclerViewItemClickListener != null) { holder.itemView.setOnClickListener(this); } if (onRecyclerViewItemLongClickListener != null) { holder.itemView.setOnClickListener(this); } if (onSubViewClickListener != null) { holder.setSubViewClickListener(onSubViewClickListener,position); } }
可以看出 这个方法里都是操作我们自定义的BaseViewHolder类。接下来就是三个空判断,也就是说,我们若是没有设置相应的点击事件,就不会初始化对应的点击事件,这样的处理方式还是很常见的。处理这个点击事件最麻烦的就是position的问题,因此我们使用的技巧是,对View对象设置tag的方式。查看源码便知道,View有个方法 setTag(Object obj); 我们就可以将对应的position赋值给这个tag,我们使用View的getTag() 方法就可以得到对应点击View的position了。在BaseRecylerAdapter类实现的点击接口和长按接口就可以知道这样的操作,类容如下。
@Override public void onClick(View v) { if (v.getTag() != null) { int position = (int) v.getTag(); onRecyclerViewItemClickListener.onItemClick(position); } } @Override public boolean onLongClick(View v) { if (v.getTag() != null){ int position = (int)v.getTag(); onRecyclerViewItemLongClickListener.onItemLongClick(position); } return true; }
BaseViewHolder类
public abstract class BaseViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ private BaseRecyclerAdapter.OnSubViewClickListener onSubViewClickListener; public BaseViewHolder(View itemView) { super(itemView); findViewById(itemView); } /** * 传入子项点击事件所需参数 * @param listener 自定义的接口 * @param tagPosition tag */ public void setSubViewClickListener(BaseRecyclerAdapter.OnSubViewClickListener listener, int tagPosition){ this.onSubViewClickListener = listener; initSubViewClick(tagPosition); } /** * 通过id匹配控件(开发者自行实现) * @param itemView 父布局 */ abstract protected void findViewById(View itemView); /** * 用于装载数据(开发者自行实现) * @param position 当前位置 */ abstract protected void onBind(int position); /** * 初始化子项的点击事件(为子项设置tag) * @param tagPosition tag */ protected void initSubViewClick(int tagPosition){ } /** * 实现子项点击事件的转发 * @param v */ @Override public void onClick(View v) { if (v.getTag() != null) { int position = (int) v.getTag(); onSubViewClickListener.onSubViewClick(v,position); } } }
这是个抽象类,也就是说,在使用的时候需要实现其中的抽象方法。为了逻辑清晰,我在这里写了两个抽象方法
/** * 通过id匹配控件(开发者自行实现) * @param itemView 父布局 */ abstract protected void findViewById(View itemView); /** * 用于装载数据(开发者自行实现) * @param position 当前位置 */ abstract protected void onBind(int position);
看注释也就很清楚这两个方法的作用是什么,这里就不多说了。
到此,我们已经实现了itemView的点击和长按事件,接下来我们来实现对itemView子项的点击事件。
在BaseViewHolder类中,也实现了一个View的点击事件接口。子项的点击方式和itemView的点击事件是一样的套路,使用tag。接下来我们来看个例子,就明白了。
public class RecyclerAdapterMyActivity extends BaseRecyclerAdapter{ private List<MyActivityBean> list; public RecyclerAdapterMyActivity(List<MyActivityBean>list){ this.list = list; } @Override public BaseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_myactivity_activity,parent,false); ViewHolder holder = new ViewHolder(view); return holder; } @Override public int getItemCount() { return list.size(); } public class ViewHolder extends BaseViewHolder { private TextView tv_name,tv_title,tv_content; private Button activityBtnChat; private Button activityBtnCancel; ViewHolder(View itemView) { super(itemView); } @Override protected void findViewById(View itemView) { tv_name = itemView.findViewById(R.id.tv_my_activity_name); tv_title = itemView.findViewById(R.id.tv_my_activity_title); tv_content = itemView.findViewById(R.id.tv_my_activity_content); activityBtnChat = itemView.findViewById(R.id.activity_btn_chat); activityBtnCancel = itemView.findViewById(R.id.activity_btn_cancel); } @Override protected void onBind(int position) { MyActivityBean bean = list.get(position); tv_name.setText(bean.getName()); tv_title.setText(bean.getTitle()); tv_content.setText(bean.getContent()); } @Override protected void initSubViewClick(int tagPosition) { activityBtnChat.setTag(tagPosition); activityBtnCancel.setTag(tagPosition); activityBtnChat.setOnClickListener(this); activityBtnCancel.setOnClickListener(this); } } }
这段代码是最近项目中的一小段代码。其中,adapter类继承BaseRecyclerAdapter,viewHolder类继承BaseViewHolder。尤其要注意的是ViewHolder的构造方法中一定要有super(itemView); 其余的方法都会按照正确的逻辑执行。若要实现itemView的子项点击事件,需要重写父类的initSubViewClick(int tagPosition) ; 方法。其中参数tagPosition便是对应的itemVIew处于RecyclerView中的位置。在这里是为两个button添加点击事件,先为其设置tag,再设置点击事件,我们这里的setOnClickListener(this) ; 参数传的是this,是因为,我们再父类中实现了View的onClick(View v); 方法。
这样,我们便完成了各类点击事件。
使用方法也很简单,就是直接操作你的adapter就可以了,调用adapter.setXxxx(...) 即可方便地实现各种点击事件。当然,要是你地需求是Touchu事件,或子项地长按事件等,都可以通过这样类似地方式来实现。
最后
方法不止一种,这样地操作方式,这只是我的一种思考。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
本文向大家介绍详解Android中点击事件的几种实现方式,包括了详解Android中点击事件的几种实现方式的使用技巧和注意事项,需要的朋友参考一下 在之前博文中多次使用了点击事件的处理实现,有朋友就问了,发现了很多按钮的点击实现,但有很多博文中使用的实现方式有都不一样,到底是怎么回事。今天我们就汇总一下点击事件的实现方式。 点击事件的实现大致分为以下三种: (1)Activity 实现接口方式实现
本文向大家介绍Android Button点击事件的四种实现方法,包括了Android Button点击事件的四种实现方法的使用技巧和注意事项,需要的朋友参考一下 Android中Button四种点击事件实现方式,具体内容如下 1.Xml添加监听属性,这里添加的doClick。 在Activity中添加doClick实现方法。Activity中实现的方法要和XML添加的属性名相同,不建议实际开发中
本文向大家介绍Android 中ListView的Item点击事件失效的快速解决方法,包括了Android 中ListView的Item点击事件失效的快速解决方法的使用技巧和注意事项,需要的朋友参考一下 在平常的开发过程中,我们的ListView可能不只是简单的显示下文本或者按钮,更多的是显示复杂的布局,这样的话,我们就得自己写布局和自定义adapter了,一般是继承于BaseAdapter,示例
本文向大家介绍iOS下Safari点击事件失效的解决方法,包括了iOS下Safari点击事件失效的解决方法的使用技巧和注意事项,需要的朋友参考一下 前言 本文主要给大家介绍了关于在iOS下Safari浏览器点击事件失效的相关解决方案,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。 问题描述 当使用委托给一个元素添加click事件时,如果事件是委托到 document 或 body
本文向大家介绍Android点击事件的实现方式,包括了Android点击事件的实现方式的使用技巧和注意事项,需要的朋友参考一下 在之前博文中多次使用了点击事件的处理实现,有朋友就问了,发现了很多按钮的点击实现,但有很多博文中使用的实现方式有都不一样,到底是怎么回事。今天我们就汇总一下点击事件的实现方式。 点击事件的实现大致分为以下三种: (1)Activity 实现接口方式实现点击事件(经常使用)
本文向大家介绍Android防止按钮过快点击造成多次事件的解决方法,包括了Android防止按钮过快点击造成多次事件的解决方法的使用技巧和注意事项,需要的朋友参考一下 问题 onClick事件是Android开发中最常见的事件。比如,一个submitButton,功能是点击之后会提交一个订单, 则一般代码如下,其中submitOrder()函数会跳转到下一页进行处理 : 正常情况下这段代码是没什么