Android小記:RecyclerView添加Item點(diǎn)擊事件監(jiān)聽

自從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)造器中需要我們傳入ContextOnGestureListener,下面是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)氮唯,歡迎指教,謝謝姨伟!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惩琉,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子夺荒,更是在濱河造成了極大的恐慌瞒渠,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件般堆,死亡現(xiàn)場(chǎng)離奇詭異在孝,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)淮摔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門私沮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人和橙,你說我怎么就攤上這事仔燕。” “怎么了魔招?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵晰搀,是天一觀的道長。 經(jīng)常有香客問我办斑,道長外恕,這世上最難降的妖魔是什么杆逗? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮鳞疲,結(jié)果婚禮上罪郊,老公的妹妹穿的比我還像新娘。我一直安慰自己尚洽,他們只是感情好悔橄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著腺毫,像睡著了一般癣疟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上潮酒,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天睛挚,我揣著相機(jī)與錄音,去河邊找鬼澈灼。 笑死竞川,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叁熔。 我是一名探鬼主播委乌,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼荣回!你這毒婦竟也來了遭贸?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤心软,失蹤者是張志新(化名)和其女友劉穎壕吹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體删铃,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡耳贬,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了猎唁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咒劲。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖诫隅,靈堂內(nèi)的尸體忽然破棺而出腐魂,到底是詐尸還是另有隱情,我是刑警寧澤逐纬,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布蛔屹,位于F島的核電站,受9級(jí)特大地震影響豁生,放射性物質(zhì)發(fā)生泄漏兔毒。R本人自食惡果不足惜漫贞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望育叁。 院中可真熱鬧绕辖,春花似錦、人聲如沸擂红。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽昵骤。三九已至,卻和暖如春肯适,著一層夾襖步出監(jiān)牢的瞬間变秦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工框舔, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蹦玫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓刘绣,卻偏偏與公主長得像樱溉,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子纬凤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容