Android中解决RecyclerView各种点击事件的方法
完美解决RecyclerView点击事件、长按事件、子项点击事件
自从Google推出了RecyclerView之后,便可以完全取代ListView,个人感觉唯一的美中不足是对于itemView的各种点击事件不够完美。观点只代表个人看法。应最近项目需求实现itemView的子项点击事件,便写篇博客记录一下,若是能够帮到你,我深感荣幸。接下来,便对RecyclerView进行简单的封装,使得它更方便实现各种点击事件。
我们都知道,对与RecyclerView的使用,是创建一个adapter类,然后在adapter类中再创建一个ViewHolder的内部类。我们要做的,正是对这两个类进行封装,让其实现itemView点击事件、长按事件、子项点击事件。
首先,我的处理方式是,对于开发者来说,只需要对adapter进行setxxx()方法的调用,例如设置itemView的点击事件:adapter.setOnRecyclerViewItemClickListener(...);对该方法传入自定义的接口即可。也就是说,我们需要自定义一个adapter类。那我们就先创建一个类,命名为BaseRecylerAdapter,此后,我们也应当创建一个BaseViewHolder类,接下来开始搞事情。
BaseRecylerAdapter类
publicabstractclassBaseRecyclerAdapterextendsRecyclerView.AdapterimplementsView.OnClickListener ,View.OnLongClickListener{ privateOnRecyclerViewItemClickListeneronRecyclerViewItemClickListener; privateOnRecyclerViewItemLongClickListeneronRecyclerViewItemLongClickListener; privateOnSubViewClickListeneronSubViewClickListener; @Override publicvoidonBindViewHolder(BaseViewHolderholder,intposition){ 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); } } publicvoidsetOnRecyclerViewItemClickListener(OnRecyclerViewItemClickListeneronRecyclerViewItemClickListener){ this.onRecyclerViewItemClickListener=onRecyclerViewItemClickListener; } publicvoidsetOnRecyclerViewItemLongClickListener(OnRecyclerViewItemLongClickListeneronRecyclerViewItemLongClickListener){ this.onRecyclerViewItemLongClickListener=onRecyclerViewItemLongClickListener; } publicvoidsetOnSubViewClickListener(OnSubViewClickListenerlistener){ this.onSubViewClickListener=listener; } @Override publicvoidonClick(Viewv){ if(v.getTag()!=null){ intposition=(int)v.getTag(); onRecyclerViewItemClickListener.onItemClick(position); } } @Override publicbooleanonLongClick(Viewv){ if(v.getTag()!=null){ intposition=(int)v.getTag(); onRecyclerViewItemLongClickListener.onItemLongClick(position); } returntrue; } publicinterfaceOnRecyclerViewItemClickListener{ voidonItemClick(intposition); } publicinterfaceOnSubViewClickListener{ voidonSubViewClick(Viewv,intposition); } publicinterfaceOnRecyclerViewItemLongClickListener{ voidonItemLongClick(intposition); } }
可以看到我们在类中创建了三个接口类
publicinterfaceOnRecyclerViewItemClickListener{
voidonItemClick(intposition);
}
publicinterfaceOnSubViewClickListener{
voidonSubViewClick(Viewv,intposition);
}
publicinterfaceOnRecyclerViewItemLongClickListener{
voidonItemLongClick(intposition);
}
这三个接口便是用于点击事件的回调,看名字就能分别出各自的功能。itemView的点击回调publicinterfaceOnRecyclerViewItemClickListener,itemView的长按publicinterfaceOnRecyclerViewItemLongClickListener,子项View的点击回调publicinterfaceOnSubViewClickListener。都是点击事件的处理,没有点击发送怎么行呢,对吧!所以,这个类还实现了View.OnClickListener和View.OnLongClickListener这两个接口,本别实现itemView的点击事件和长按事件。
可以看到,BaseRecyclerAdapter继承自RecyclerView.Adapter
@Override
publicvoidonBindViewHolder(BaseViewHolderholder,intposition){
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(Objectobj);我们就可以将对应的position赋值给这个tag,我们使用View的getTag()方法就可以得到对应点击View的position了。在BaseRecylerAdapter类实现的点击接口和长按接口就可以知道这样的操作,类容如下。
@Override
publicvoidonClick(Viewv){
if(v.getTag()!=null){
intposition=(int)v.getTag();
onRecyclerViewItemClickListener.onItemClick(position);
}
}
@Override
publicbooleanonLongClick(Viewv){
if(v.getTag()!=null){
intposition=(int)v.getTag();
onRecyclerViewItemLongClickListener.onItemLongClick(position);
}
returntrue;
}
BaseViewHolder类
publicabstractclassBaseViewHolderextendsRecyclerView.ViewHolderimplementsView.OnClickListener{
privateBaseRecyclerAdapter.OnSubViewClickListeneronSubViewClickListener;
publicBaseViewHolder(ViewitemView){
super(itemView);
findViewById(itemView);
}
/**
*传入子项点击事件所需参数
*@paramlistener自定义的接口
*@paramtagPositiontag
*/
publicvoidsetSubViewClickListener(BaseRecyclerAdapter.OnSubViewClickListenerlistener,inttagPosition){
this.onSubViewClickListener=listener;
initSubViewClick(tagPosition);
}
/**
*通过id匹配控件(开发者自行实现)
*@paramitemView父布局
*/
abstractprotectedvoidfindViewById(ViewitemView);
/**
*用于装载数据(开发者自行实现)
*@paramposition当前位置
*/
abstractprotectedvoidonBind(intposition);
/**
*初始化子项的点击事件(为子项设置tag)
*@paramtagPositiontag
*/
protectedvoidinitSubViewClick(inttagPosition){
}
/**
*实现子项点击事件的转发
*@paramv
*/
@Override
publicvoidonClick(Viewv){
if(v.getTag()!=null){
intposition=(int)v.getTag();
onSubViewClickListener.onSubViewClick(v,position);
}
}
}
这是个抽象类,也就是说,在使用的时候需要实现其中的抽象方法。为了逻辑清晰,我在这里写了两个抽象方法
/** *通过id匹配控件(开发者自行实现) *@paramitemView父布局 */ abstractprotectedvoidfindViewById(ViewitemView); /** *用于装载数据(开发者自行实现) *@paramposition当前位置 */ abstractprotectedvoidonBind(intposition);
看注释也就很清楚这两个方法的作用是什么,这里就不多说了。
到此,我们已经实现了itemView的点击和长按事件,接下来我们来实现对itemView子项的点击事件。
在BaseViewHolder类中,也实现了一个View的点击事件接口。子项的点击方式和itemView的点击事件是一样的套路,使用tag。接下来我们来看个例子,就明白了。
publicclassRecyclerAdapterMyActivityextendsBaseRecyclerAdapter{
privateListlist;
publicRecyclerAdapterMyActivity(Listlist){
this.list=list;
}
@Override
publicBaseViewHolderonCreateViewHolder(ViewGroupparent,intviewType){
Viewview=LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_myactivity_activity,parent,false);
ViewHolderholder=newViewHolder(view);
returnholder;
}
@Override
publicintgetItemCount(){
returnlist.size();
}
publicclassViewHolderextendsBaseViewHolder{
privateTextViewtv_name,tv_title,tv_content;
privateButtonactivityBtnChat;
privateButtonactivityBtnCancel;
ViewHolder(ViewitemView){
super(itemView);
}
@Override
protectedvoidfindViewById(ViewitemView){
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
protectedvoidonBind(intposition){
MyActivityBeanbean=list.get(position);
tv_name.setText(bean.getName());
tv_title.setText(bean.getTitle());
tv_content.setText(bean.getContent());
}
@Override
protectedvoidinitSubViewClick(inttagPosition){
activityBtnChat.setTag(tagPosition);
activityBtnCancel.setTag(tagPosition);
activityBtnChat.setOnClickListener(this);
activityBtnCancel.setOnClickListener(this);
}
}
}
这段代码是最近项目中的一小段代码。其中,adapter类继承BaseRecyclerAdapter,viewHolder类继承BaseViewHolder。尤其要注意的是ViewHolder的构造方法中一定要有super(itemView);其余的方法都会按照正确的逻辑执行。若要实现itemView的子项点击事件,需要重写父类的initSubViewClick(inttagPosition);方法。其中参数tagPosition便是对应的itemVIew处于RecyclerView中的位置。在这里是为两个button添加点击事件,先为其设置tag,再设置点击事件,我们这里的setOnClickListener(this); 参数传的是this,是因为,我们再父类中实现了View的onClick(Viewv);方法。
这样,我们便完成了各类点击事件。
使用方法也很简单,就是直接操作你的adapter就可以了,调用adapter.setXxxx(...)即可方便地实现各种点击事件。当然,要是你地需求是Touchu事件,或子项地长按事件等,都可以通过这样类似地方式来实现。
最后
方法不止一种,这样地操作方式,这只是我的一种思考。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。