RecyclerView的超強輔助Graywater——點選事件
關於Graywater的系列文章
上一篇寫了Graywater的基礎使用,但是沒講點選事件,這一篇文章就把點選事件給補充上。還是使用的基礎實操篇中的GraywaterPrimaryDemo繼續寫。
先展示點選效果圖:
在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上,由此來組成第一篇文章中所展示的對映網狀關係,並通過對映關係,來快速查詢所需要的類。
到這裡,基本上點選事件就講完了,有什麼錯誤或說的不清楚的地方歡迎大家指正。
如果對你有幫助的話,點贊、評論、讚賞都是對我的鼓勵,也是支援我寫下去的動力,謝謝!