RecyclerView的出现代替了ListView的“霸主地位”,关于RecyclerView的好处这里不再多说,不过用过RecyclerView的朋友们都知道,这个傲娇的View没有提供setOnItemClickListener方法,如果我们要实现这样的功能该怎么做呢?翻遍了网上所有的实现方式,下面介绍两中我觉得还不错的方法。
通过ViewHolder传入监听接口:
RecyclerView自己提供了ViewHolder,了解的朋友们都知道,在RecyclerView的ViewHolder构造方法中,有这么一个参数:View itemView
class MyViewHolder extends ViewHolder {
ImageView categoryImage;
TextView categoryName;
public MyViewHolder(View itemView, OnItemClickListener onItemClickListener) {
super(itemView);
categoryName = (TextView) itemView.findViewById(R.id.category_name);
categoryImage = (ImageView) itemView.findViewById(R.id.category_image);
itemView.setOnClickListener(v -> onItemClickListener.OnItemClick(getPosition(), v));
}
}
如上述代码是我写的一个例子,ViewHolder的构造方法中,有一个itemView的参数,而这个参数就是RecyclerView中的每个item,而我们要设置点击监听的不就是它么,所以从这里入手,我们可以传一个自定义监听接口给ViewHolder作为构造方法的参数,然后在里面为itemView设置这个监听接口(在onClick中调用我们自己写的接口的方法)
然后再把视线转到RecyclerView的onCreateViewHolder方法中,这个方法是创建ViewHolder的地方,看代码:
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).
inflate(R.layout.item_horizontal_listview, parent, false);
return new MyViewHolder(view, onItemClickListener);
}
从上面的代码可以看到,我们首先从xml中inflate了一个item的view进来,然后将这个view以及一个我们自己写的监听接口实例传给了ViewHolder的构造方法。最终返回了一个ViewHolder实例,这样我们就间接地实现了对item的点击监听。
当然了,这个onItemClickListenr还需要我们提供一个对外的设置接口,这个设置接口可以写在Adapter中,因为我们的ViewHolder就是在Adapter里面的。
下面贴上一个完整的示例代码:
public class HorizontalListViewAdapter extends Adapter {
//自定义监听接口
private OnItemClickListener onItemClickListener;
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).
inflate(R.layout.item_horizontal_listview, parent, false);
//从这里将接口实例传给ViewHolder
return new MyViewHolder(view, onItemClickListener);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
//代码省略
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public int getItemCount() {
return mItems.size();
}
class MyViewHolder extends ViewHolder {
ImageView categoryImage;
TextView categoryName;
public MyViewHolder(View itemView, OnItemClickListener onItemClickListener) {
super(itemView);
categoryName = (TextView) itemView.findViewById(R.id.category_name);
categoryImage = (ImageView) itemView.findViewById(R.id.category_image);
itemView.setOnClickListener(v -> onItemClickListener.OnItemClick(getPosition(), v));
}
}
//向外提供设置监听接口
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
}
/**
* item点击事件监听接口
*/
interface OnItemClickListener {
void OnItemClick(int position, View view);
}
这个实现方式看起来还是比较“优雅的”,网上不少人都是用这个方法,我觉得也挺不错,就mark一下;
接下来再说一个我觉得也比较巧妙的方式,这个方式是我的一个好基友启发了我:重写addView方法:
重写addView方法:
众所周知,一个ViewGroup是通过addView方法来添加自己的子view的,那么RecyclerView也不例外,我们可以在addView方法中,对传进来的每一个child设置点击监听.
addView方法有很多个,经过测试,下面这个方法总是会被调用
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
}
于是我们就拿它“开刀”
这么一来问题就很简单了,这个child参数就是我们要设置监听的对象,对他设置OnClickListener,然后在OnClick方法里面调用我们自己写的接口方法,问题就搞定了。
虽然这个方法我觉得很巧妙(觉得巧妙是因为当我第一次看到这种写法时,不由得惊讶:这样也行?!),但是又隐隐约约觉得这样做不太“友好”,才学疏浅,希望各路大神前来指点一二。