2016-03-29 122 views
10

問題從消費觸摸事件

防止RecyclerView我試圖模仿谷歌播放應用程序的具體行爲。

當你滾動瀏覽「Top遊戲」這樣的類別並觸摸該列表時,該單元以及RecyclerView可處理觸摸事件,因此當您在處理觸摸事件時,由於出現漣漪,你停下手指以及滾動停下來。或者,如果您在列表仍在移動時點擊某個單元格,則該內容會立即打開。

的默認行爲是滾動,如果你把你的手指下降,而它的移動立即停止,併爲它然後消耗的是觸摸事件,這意味着細胞永遠不會講述了聯繫。這是令人難以置信的刺激性,當您的應用程序的主要內容是在一個RecyclerView如果用戶持續滾動,然後點擊一個細胞,它要求他們點擊兩次,因爲第一次點擊已經停止滾動消耗,即使該名單幾乎沒有移動。

就我嘗試遠

起初我還以爲必須有RecyclerView裏面的一些種類標誌的告訴它不消耗觸摸事件。我瀏覽了Android源代碼並通過Android文檔路由無效。

然後我嘗試用onInterceptTouchEvent捕獲觸摸事件,並手動告訴我的觀點,它被觸摸;

@Override 
public boolean onInterceptTouchEvent(MotionEvent event) { 
    View myCell = recyclerView.findChildViewUnder(event.getX(), event.getY()); 
    myCell.dispatchTouchEvent(event); 
    return super.onInterceptTouchEvent(event); 
} 

這裏,dispatchTouchEvent似乎並沒有這樣做,即使我得到的觀點有我在適配器設置相應的標籤什麼。

我試過用我的代碼機槍在各個角度拍攝這個問題;與requestDisallowInterceptTouchEvent玩,手動呼叫onTouch和覆蓋RecyclerView及以後的所有方式的聽衆。

似乎沒有任何工作。我確定這件事必須有一個優雅的解決方案,並且我已經在瘋狂的道路上的某個重要細節上掠過了?特別是因爲Google自己的應用程序以這種方式行事。

請幫忙! :) 謝謝。

解決方案

由於Jagoan霓虹燈的解決方案已被發現。爲了便於使用,我最終將自己的答案包裝在自定義RecyclerView中。

public class MultiClickRecyclerView extends RecyclerView { 
    public MultiClickRecyclerView(Context context) { 
     super(context); 
    } 

    public MultiClickRecyclerView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public MultiClickRecyclerView(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent event) { 
     if (event.getAction() == MotionEvent.ACTION_DOWN && this.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) { 
      this.stopScroll(); 
     } 
     return super.onInterceptTouchEvent(event); 
    } 
} 

回答

9

首先,你應該定義一個OnItemTouchListener,或許這樣的全局變量:

RecyclerView.OnItemTouchListener mOnItemTouchListener = new RecyclerView.OnItemTouchListener() { 
    @Override 
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 
     if (e.getAction() == MotionEvent.ACTION_DOWN && rv.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) { 
      Log.d(TAG, "onInterceptTouchEvent: click performed"); 
      rv.findChildViewUnder(e.getX(), e.getY()).performClick(); 
      return true; 
     } 
     return false; 
    } 

    @Override 
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {} 

    @Override 
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {} 
}; 

爲什麼ACTION_DOWN和SCROLL_STATE_SETTLING?

當您在RecyclerView上執行觸摸操作時,會觸發ACTION_DOWN運動事件,並且在該確切時間點RecyclerView將其滾動狀態更改爲SCROLL_STATE_SETTLING,因爲它試圖停止滾動。這正是您想要執行點擊的時間。

並記得返回true,以便告訴您的RecyclerView您已經使用了MotionEvent。否則,您的performClick()可能會被多次調用。

將它添加到您的RecyclerView在的onResume和在onPause刪除它,就這麼簡單;)

UPDATE

添加一個空檢查,當你在做findChildViewUnder - 它返回null當你沒有觸及特定的細胞。

View childView = rv.findChildViewUnder(e.getX(), e.getY()); 
if (childView != null) childView.performClick(); 

更新2

原來,從滾動停止RecyclerView就足夠了。這樣做代替:

@Override 
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) { 
     if (e.getAction() == MotionEvent.ACTION_DOWN && rv.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) 
      rv.stopScroll(); 
     return false; 
    } 
+0

我今天早上實現了你的答案,我們快到了!真奇怪;這個解決方案似乎在大約30%的時間內工作,這取決於我事先拖動的速度有多慢。我一直在註銷運動事件和滾動狀態,從什麼時候起,什麼時候不起作用似乎沒有什麼區別。 如果我快速滾動列表,然後點擊並按住我的手指,它幾乎不會註冊觸摸並顯示漣漪(如Google Play應用程序那樣)。它是不斷爲你工作嗎?我正在使用2個跨度的網格佈局,但我不認爲這會有所作爲。 – vguzzi

+0

你見過我的第二次編輯嗎? –

+0

是的,我目前在停止滾動視圖實現。我也嘗試了以前的建議。 – vguzzi