关于Graywater的系列文章
上一篇写了Graywater的基础使用,但是没讲点击事件,这一篇文章就把点击事件给补充上。还是使用的基础实操篇中的GraywaterPrimaryDemo继续写。
先展示点击效果图:
Graywater点击事件.gif在RecyclerView中如果需要点击事件,我们通常会给RecyclerViewd.Adapter传入一个我们自定义的接口引用,比如OnItemClickListener。然后在onBindViewHolder()方法中将需要点击事件的控件,比如Button,实现View的OnClickListener接口,再使用我们自定义的方法,最后在MainActivity中实现自定义的接口。
holder.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (clickListener != null) {
clickListener.onClickItem(position);
}
}
});
Graywater跟前者也是比较相似的,最大的不同的是Graywater自己提供了一个点击事件的接口(GraywaterAdapter.ActionListener)和一个点击事件代理(GraywaterAdapter.ActionListenerDelegate)来管理点击事件。通过在Binder类中传入ViewHolder所持有的接口代理,在ItemBinder中实现接口的act()方法,来完成点击事件的实现。
实际上,是GraywaterAdapter.ActionListenerDelegate代理实现了View的OnClickListener接口,然后在onClick方法中在调用GraywaterAdapter.ActionListener的act方法。
@Override
public void onClick(final View v) {
actionListener.act(model, holder, v, binders, binderIndex, obj);
}
接下来就一步步的讲解怎么实现点击事件,点击事件也可以根据上一篇文章中代码的顺序来写。
1. 给需要点击事件的控件添加id值
每个Item都由一个RelativeLayout作为最外层的控件,里面放了一个TextView和一个ImageView,给RelativeLayout添加android:id="@+id/item_layout"属性
2. 在对应ViewHolder类中添加对应的View并创建ActionListenerDelegate的对象
在EntertainViewHolder里面添加RelativeLayout的控件。
重点!需要在ViewHolder中创建代理对象,使用holder来统一管理所有的view和点击代理对象。创建ActionListenerDelegate对象时候需要也需要传入对应的model和viewholder的泛型参数,当然这里就是EntertainPrimitive和EntertainViewHolder。
private GraywaterAdapter.ActionListenerDelegate<EntertainPrimitive, EntertainViewHolder>
mActionListenerDelegate = new GraywaterAdapter.ActionListenerDelegate<>();
别忘记在最后也要添加对应的get方法。
3.在Binder类的bind方法中setOnClickListener()
Graywater官方Demo中,要想实现点击事件,就必须要在bind方法里让点击代理getmActionListenerDelegate执行update()方法。看Graywater源码可以知道update方法实际上就是把相关参数都保存下来,然后在act方法中把相关的引用传过去使用。
在update方法后,需要点击事件的View就可以在setOnClickListener()中传入点击代理了,最后记得要在unbind()方法中给setOnClickListener()传入null值做清理。
@Override
public void bind(@NonNull EntertainPrimitive model, @NonNull EntertainViewHolder holder, @NonNull List<GraywaterAdapter.Binder<? super EntertainPrimitive, ? extends EntertainViewHolder>>
binders, int binderIndex, @NonNull GraywaterAdapter.ActionListener<EntertainPrimitive, EntertainViewHolder> actionListener) {
Picasso.get().load(model.getUrls().get(binderIndex)).placeholder(R.mipmap.ic_launcher).into(holder.getImg());
holder.getTitle().setText(model.getTitles().get(binderIndex));
holder.getmActionListenerDelegate().update(actionListener, model, holder, binders, binderIndex, null);
holder.getMainLayoutView().setOnClickListener(holder.getmActionListenerDelegate());
}
@Override
public void unbind(@NonNull EntertainViewHolder holder) {
holder.getMainLayoutView().setOnClickListener(null);
}
update()方法所需要传入的参数基本上就是bind方法中的参数,需要注意的是最后一个Object参数,这个Object参数是用来传递我们想要传递的值的,类似Intent传值的作用一样。一般都用不到,可以直接传null。
holder.getmActionListenerDelegate().update(actionListener, model, holder, binders, binderIndex, null);
4.ItemBinder类实现GraywaterAdapter.ActionListener接口,并实现act()方法
EntertainItemBinder需要实现GraywaterAdapter.ActionListener接口,然后就可以在act方法中具体实现我们的点击事件了。
在GraywaterAdapter.ActionListener接口中需要传入model的泛型参数和viewholder的泛型参数,在EntertainItemBinder中,就传入对应的EntertainPrimitive和EntertainViewHolder。
看一下act方法的实现,其实就是类似RecyclerView.Adapter中的实现:
@Override
public void act(@NonNull EntertainPrimitive model, @NonNull EntertainViewHolder holder, @NonNull View v, @NonNull List<GraywaterAdapter.Binder<? super EntertainPrimitive, ? extends
EntertainViewHolder>> binders, int binderIndex, @Nullable Object obj) {
switch (v.getId()) {
case R.id.item_layout:
onItemClickListener.onClickItem(model.getTitles().get(binderIndex));
break;
}
}
5.写接口传入,MainActivity实现接口
一般在写点击事件时,我们一般会习惯自定义一个点击事件接口,这里也不例外,我自定义了一个OnItemClickListener接口。让MainActivity实现了这个接口,并将接口传入PrimitiveAdapter中。
public interface OnItemClickListener {
void onClickItem(String name);
}
MainActivity实现了onClickItem方法,就可以使用传过来的name参数做相应的业务处理了。
看一下OnItemClickListener引用的传递顺序。
首先是MainActivity
mPrimitiveAdapter = new PrimitiveAdapter(this); //因为MainActivity实现了OnItemClickListener接口,所以传入this
mRecyclerView.setAdapter(mPrimitiveAdapter);
再是PrimitiveAdapter的构造方法,将OnItemClickListener传给EntertainItemBinder。
public PrimitiveAdapter(OnItemClickListener listener) {
register(new EntertainViewHolderCreator(), EntertainViewHolder.class); //将creator和对应的viewholder绑定
EntertainBinder entertainBinder = new EntertainBinder();
EntertainItemBinder entertainItemBinder = new EntertainItemBinder(entertainBinder, listener);
register(EntertainPrimitive.class, entertainItemBinder, entertainItemBinder); //将itemBinder和指定的数据类型绑定
}
注意构造方法中的第二个register()方法的第三个参数也是entertainItemBinder,从源码可知,要求传入的参数是GraywaterAdapter.ActionListener,也就是在ItemBinder实现该接口后就传入ItemBinder,否则就传入null。
protected void register(@NonNull final MT modelType,
@NonNull final ItemBinder<? extends T, ? extends VH> parts,
@Nullable final ActionListener<? extends T, ? extends VH> listener) {
mItemBinderMap.put(modelType, parts);
mActionListenerMap.put(modelType, listener);
}
Graywater有5个基本变量,mItemBinderMap和mActionListenerMap就是其中两个,这两个变量都是Map类型。Graywater中5个基本变量除开mItems不是字典类型,其他4个都是这种字典类型。这是Graywater的核心,以字典的方式,将model映射到viewholder上。register就是在匹配映射关系,将viewholder和viewholdercreator映射起来。将model映射到ItemBinder上,将model映射到Actionlistener上,由此来组成第一篇文章中所展示的映射网状关系,并通过映射关系,来快速查找所需要的类。
原理图1.png到这里,基本上点击事件就讲完了,有什么错误或说的不清楚的地方欢迎大家指正。
P.S.
Graywater 官方Demo Github地址
GraywaterPrimaryDemo Github地址 如果对大家有帮助的话,star就是对我的鼓励。
如果对你有帮助的话,点赞、评论、赞赏都是对我的鼓励,也是支持我写下去的动力,谢谢!
网友评论