自從Android5.0,Google發(fā)布RecyclerView
以來运嗜,逐漸代替了傳統(tǒng)的ListView
壶辜,因?yàn)镽ecyclerView更加強(qiáng)大,更加靈活担租,但是砸民,由于官方未實(shí)現(xiàn)RecyclerView的Item點(diǎn)擊事件,所以需要自行實(shí)現(xiàn)。下面就是我在使用RecyclerView的過程中反惕,總結(jié)的添加點(diǎn)擊事件的幾種方法。
方式一:通過RecyclerView的addOnItemTouchListener()方法
使用RecyclerView提供的addOnItemTouchListener()
方法演侯,為Item添加觸摸回調(diào)姿染,在觸摸事件處理中,實(shí)現(xiàn)Item點(diǎn)擊蚌本;
通過源碼得知盔粹,RecyclerView有一個(gè)添加Item觸摸事件的方法:
/**
* Add an {@link OnItemTouchListener} to intercept touch events before they are dispatched
* to child views or this view's standard scrolling behavior.
*
* <p>Client code may use listeners to implement item manipulation behavior. Once a listener
* returns true from
* {@link OnItemTouchListener#onInterceptTouchEvent(RecyclerView, MotionEvent)} its
* {@link OnItemTouchListener#onTouchEvent(RecyclerView, MotionEvent)} method will be called
* for each incoming MotionEvent until the end of the gesture.</p>
*
* @param listener Listener to add
* @see SimpleOnItemTouchListener
*/
public void addOnItemTouchListener(@NonNull OnItemTouchListener listener) {
mOnItemTouchListeners.add(listener);
}
此方法需要傳入一個(gè)OnItemTouchListener
,OnItemTouchListener代碼如下:
public interface OnItemTouchListener {
boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e);
void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept);
}
同時(shí)程癌,RecyclerView還提供了一個(gè)子類SimpleOnItemTouchListener
:
/**
* An implementation of {@link RecyclerView.OnItemTouchListener} that has empty method
* bodies and default return values.
* <p>
* You may prefer to extend this class if you don't need to override all methods. Another
* benefit of using this class is future compatibility. As the interface may change, we'll
* always provide a default implementation on this class so that your code won't break when
* you update to a new version of the support library.
*/
public static class SimpleOnItemTouchListener implements RecyclerView.OnItemTouchListener {
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
return false;
}
@Override
public void onTouchEvent(@NonNull RecyclerView rv, @NonNull MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
}
我們可以通過此類實(shí)現(xiàn)Item點(diǎn)擊功能舷嗡;
寫一個(gè)類ItemTouchHelper
類繼承自SimpleOnItemTouchListener
,重寫onInterceptTouchEvent
方法嵌莉,在onInterceptTouchEvent中進(jìn)行事件處理进萄;
@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView recyclerView,
@NonNull MotionEvent motionEvent) {
return mGestureDetectorCompat.onTouchEvent(motionEvent);
}
這里的mGestureDetectorCompat
,是一個(gè)GestureDetectorCompat
輔助工具锐峭,繼續(xù)觀察源碼中鼠,GestureDetectorCompat構(gòu)造器中需要我們傳入Context
和OnGestureListener
,下面是OnGestureListener源碼:
public interface OnGestureListener {
// 用戶按下屏幕就會(huì)觸發(fā)
boolean onDown(MotionEvent e);
// 如果是按下的時(shí)間超過瞬間沿癞,而且在按下的時(shí)候沒有松開或者是拖動(dòng)的援雇,那么onShowPress就會(huì)執(zhí)行
void onShowPress(MotionEvent e);
// 一次單獨(dú)的輕擊抬起操作,也就是輕擊一下屏幕,就是普通點(diǎn)擊事件
boolean onSingleTapUp(MotionEvent e);
// 在屏幕上拖動(dòng)事件
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
// 長按觸摸屏椎扬,超過一定時(shí)長惫搏,就會(huì)觸發(fā)這個(gè)事件
void onLongPress(MotionEvent e);
// 滑屏,用戶按下觸摸屏蚕涤、快速移動(dòng)后松開
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}
通過源碼發(fā)現(xiàn)筐赔,onSingleTapUp
方法會(huì)在觸摸抬起時(shí)觸發(fā);同樣揖铜,官方也為我們提供了一個(gè)OnGestureListener
的簡單實(shí)現(xiàn)類SimpleOnGestureListener
茴丰,這個(gè)類實(shí)現(xiàn)了所有方法,但都是空實(shí)現(xiàn)天吓,我們只需要重寫onSingleTapUp
方法贿肩,并處理事件即可:
GestureDetector.OnGestureListener gl = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (child != null && mListener != null) {
mListener.onItemClick(recyclerView.getChildViewHolder(child));
return true;
}
return false;
}
}
mGestureDetectorCompat = new GestureDetectorCompat(recyclerView.getContext(), gl);
RecyclerView提供了findChildViewUnder
方法,我們可以通過事件點(diǎn)擊的坐標(biāo)獲取點(diǎn)擊的Item龄寞,再通過RecyclerView的getChildViewHolder
方法獲取Item的ViewHolder尸曼,進(jìn)而執(zhí)行我們想要的操作,至此萄焦,我們可以將點(diǎn)擊事件回調(diào)出去。方法一:通過View.setOnClickListener()方法
方式二:將點(diǎn)擊事件添加到Item的根布局上,通過Adapter回調(diào)的方式添加事件監(jiān)聽:
public class MyAdapter extends RecyclerView.Adapter<ViewHolder> {
...
@Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder viewHolder, int position) {
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null) {
listener.onItemClick(viewHolder.itemView, viewHolder.getAdapterPosition());
}
}
});
}
private OnItemClickListener listener;
public void setOnItemClickListener(OnItemClickListener listener) {
this.listener = listener;
}
public interface OnItemClickListener {
void onItemClick(View itemView, int position);
}
}
方式三:在Item添加到RecyclerView時(shí)添加點(diǎn)擊事件
RecyclerView還提供了一個(gè)addOnChildAttachStateChangeListener
方法拂封,可以為RecyclerView提供一個(gè)OnChildAttachStateChangeListener
茬射,監(jiān)聽一個(gè)View添加到RecyclerView和離開RecyclerView,我們可以在這個(gè)時(shí)候執(zhí)行一些操作來實(shí)現(xiàn)Item點(diǎn)擊:
OnChildAttachStateChangeListener listener = new RecyclerView.OnChildAttachStateChangeListener() {
@Override
public void onChildViewAttachedToWindow(@NonNull View view) {
final RecyclerView.ViewHolder viewHolder = mRecyclerView.getChildViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mListener != null){
mListener.onItemClick(viewHolder);
}
}
});
}
@Override
public void onChildViewDetachedFromWindow(@NonNull View view) {}
}
mRecyclerView.addOnChildAttachStateChangeListener(listener);
小結(jié)
以上三種實(shí)現(xiàn)方式是在開發(fā)中遇到冒签,并在網(wǎng)上獲取的實(shí)現(xiàn)方法在抛,三種方式各有優(yōu)劣,在實(shí)際開發(fā)中萧恕,可以靈活選擇刚梭。
第一種直接從觸摸事件入手,可舉一反三票唆,通過不同的邏輯進(jìn)行其他手勢(shì)的監(jiān)聽和處理朴读;第二種和第三種大同小異,均是通過View
類的setOnClickListener
方法入手實(shí)現(xiàn)走趋,同樣的也可以通過其他方式實(shí)現(xiàn)不同效果衅金。
本文僅代表個(gè)人看法,如果有誤歡迎指正簿煌,如果您有更好的實(shí)現(xiàn)氮唯,歡迎指教,謝謝姨伟!