Android觸摸事件的分發機制

參與分發的組件


  • Activity
    無onInterceptTouchEvent方法,不進行攔截,直接傳遞給子view

dispatchTouchEvent
onTouchEvent

  • ViewGroup

dispatchTouchEvent
onInterceptTouchEvent
onTouchEvent

  • View
    無onInterceptTouchEvent方法,dispatchTouchEvent返回默認時直接傳遞給onTouchEvent

dispatchTouchEvent
onTouchEvent

參與事件分發的方法


dispatchTouchEvent

  • 返回值爲默認值,有下列3種情況
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return super.dispatchTouchEvent(ev);
    }

Activity
無onInterceptTouchEvent,直接傳遞給子View
ViewGroup
調用自身onInterceptTouchEvent方法,並決定下一步事件傳遞
View
無onInterceptTouchEvent,直接調用自身onTouchEvent

  • 返回值爲true
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return true;
    }

終結傳遞,即常用術語(消費)
事件不再向下傳遞,傳遞終止,並且後續事件同樣傳遞至此爲止

  • 返回值爲false
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return false;
    }

傳遞至父view的onTouchEvent
後續事件不再經過此view的dispatchTouchEvent方法

  • 調用了super.dispatchTouchEvent(ev)
 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        super.dispatchTouchEvent(ev);
        return true/false;
    }

只要調用了super.dispatchTouchEvent(ev),就一定會進行下一步傳遞
返回值爲true,後續繼續接收事件
返回值爲false,不再接收後續事件

總結

dispatchTouchEvent可以理解爲事件分發的方法,其返回值決定了後續事件的接收,是否調用super.dispatchTouchEvent(ev)方法決定了此次事件是否繼續分發。


onInterceptTouchEvent

 public boolean onInterceptTouchEvent(MotionEvent ev) {
        return false;
 }

此方法爲事件攔截方法,方法默認返回false

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);
    }

返回值爲super.onInterceptTouchEvent(ev)或false時,表示不進行攔截,事件會繼續傳遞至子view的dispatchTouchEvent方法。

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return true;
    }

返回值爲true時,表示攔截事件,直接把事件傳遞至當前view的onTouchEvent方法,並且後續事件經由當前view的dispatchTouchEvent傳遞至onTouchEvent,不再向下傳遞且不經過onInterceptTouchEvent


onTouchEvent

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        return super.onTouchEvent(event);
    }

返回值super.onTouchEvent(event)或true時,消費事件,並且後續的MOVE UP事件會被此view攔截並傳遞至onTouchEvent。
如果處理MOVE事件時返回值爲false,那麼這個事件會消失,不會觸發父元素的onTouchEvent,後續的事件仍然會發送至此view處理。消失的事件會傳遞給activity處理

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        return false;
    }

返回值爲false時,傳遞至父view的onTouchEvent。


流程

默認流程


dispatchTouchEvent(Activity)—–>dispatchTouchEvent(ViewGroup)—–>onInterceptTouchEvent(ViewGroup)—–>dispatchTouchEvent(View)—–>onTouchEvent(View)—–>onTouchEvent(ViewGroup)—–>onTouchEvent(Activity)

onTouchEvent(ViewGroup)消費事件,後續流程


dispatchTouchEvent(Activity)—–>dispatchTouchEvent(ViewGroup)—–>onInterceptTouchEvent(ViewGroup)—–>dispatchTouchEvent(View)—–>onTouchEvent(View)—–>onTouchEvent(ViewGroup)

dispatchTouchEvent(ViewGroup)消費事件,後續流程


dispatchTouchEvent(Activity)—–>dispatchTouchEvent(ViewGroup)—–>onInterceptTouchEvent(ViewGroup)—–>dispatchTouchEvent(View)

TIPS


  • 如果我們在一個View中同時覆寫了onClick、onLongClick及onTouchEvent的話,onTouchEvent是最先捕捉到ACTION_DOWN和ACTION_UP事件的,其次纔可能觸發onClick或者onLongClick
  • onTouchListener的onTouch方法優先級比onTouchEvent高,會先觸發。假若onTouchListener中的onTouch方法返回true,表示此次事件已經被消費了,那onTouchEvent是接收不到消息的。假如onTouch方法返回false,會接着觸發onTouchEvent,反之onTouchEvent方法不會被調用。內置諸如click事件的實現等等都基於onTouchEvent,假如onTouch返回true,這些事件將不會被觸發。
  • GestureDetector類進行手勢識別
  1. 爲View或者Activity實現OnGestureListener接口,覆寫需要的手勢的回調方法。
  2. 創建一個GestureDetector對象mygesturedetector,設置其監聽器。
  3. 覆寫View或者Activity的OnTouchEvent方法,調用或返回mygesturedetector.onTouchEvent(ev),將事件交給mygesturedetector處理。
  • 在ScrollView內重寫方法時,務必調用super.dispatchTouchEvent(ev),否則自帶慣性滑動將會失效

參考:
Android中Touch事件傳遞總結
圖解 Android 事件分發機制

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章