? ? ?首先,本文不會涉及完全理論性的關于事件分發的講解,而是將一部分理論應用到該實例中。因為事件分發理論太多、太復雜,如果不是處理很復雜的自定義View,只需要用到其中一小部分就可以完成任務了,對此,我們必須:
從理論中來,到實踐中去
為什么重寫dispatchTouchEvent()
? ? ?在寫自定義View的時候,一旦涉及到事件分發,往往會重寫onTouchEvent(),而這里卻是重寫了dispatchTouchEvent(),為什么呢?要回答這個問題,就必須說明dispatchTouchEvent()是干什么的。
? ? ?當事件到達View時,如果他是個普通的View,則沒有必要去分發事件,直接調用到onTouchEvent來決定是否要處理該事件;如果他是個ViewGroup,那么他就必須調用dispatchTouchEvent()把事件分發下去,只有當ViewGroup主動攔截了事件,或者所有的子孩子都不處理這個事件,該事件才會傳遞到他的onTouchEvent()方法。
? ? ?在該例子中,PtrFrameLayout必須決定事件是自己處理(調用scroll方法),還是傳遞給子孩子(調用super.dispatchTouchEvent()。試想,如果我們重寫的是onTouchEvent,而且content是一個ScrollView,那么所有的事件都會被ScrollView拿到(除非攔截,那樣又增加了復雜度)。所以,必須在分發的時候就要做出判斷。
DOWN事件的處理
問題:為什么不能直接返回super.dispatchTouchEvent()?
? ? ?如果content是原生控件,沒有設置clickListener,也沒有重寫ouTouch等,反正就是他不會處理任何事件。如普通的LinearLayout,他會所有事件的處理都是返回false,也就是告訴父控件--事件給你吧,我統統不要。那么,PtrFrameLayout的dispatchTouchEvent()也就返回false,也就是告訴他的父控件,后面的事件我也不care了,你就不要傳遞給我了。所以,后面的MOVE事件他也就接受不到了,此時控件也就滑不動了。
問題:為什么要把DOWN事件傳遞給子視圖?
? ? ?如果一個視圖沒有拿到DOWN事件,那么后續的事件他也就都拿不到了。因為父視圖不把DOWN事件往下傳遞,也就是說,后面的事件我自己都要了。
問題:正確的處理方式是怎樣?
? ? ?首先,我們要確保PtrFrameLayout無論如何都要拿到事件,對于子孩子能處理的事件,給子孩子處理,而子孩子不能處理的,則自己處理。所以,在DOWN事件中,事件要先交給子視圖,無論子視圖怎么處理,父視圖返回true,表示事件已經處理,那么后續的MOVE事件還是會先到父視圖來,而且當父視圖再次調用super.dispatchTouchEvent()把消息往下傳遞時,子視圖也能收到MOVE事件,從而實現content(如ScrollView)的滑動。
MOVE事件的處理
? ? 在滑動過程中,有時候是content滑動,有時候是PtrFrameLayout調用scroll方法執行滑動。如果想讓content滑動,直接調用super.dispatchTouchEvent(),事件會傳遞給content,他會自己處理事件;如果想讓PtrFrameLayout滑動,調用scroll方法后,返回true即可,代表事件已經處理。