?。?!注意,為了方便查看,文章中代碼都做了精簡,不是完整代碼。
事件的分發(fā)順序
Activity?—> ViewGroup?—> View
onTouch優(yōu)先于onClick執(zhí)行
如果onTouch 返回true,則在dispatchTouchEvent方法分發(fā)事件時直接return true,不會再執(zhí)行onTouchEvent(event)方法。
onTouch 在dispatchTouchEvent中執(zhí)行,onClick在onTouchEvent(event)中執(zhí)行。


TextView ImageView 默認為不可點擊狀態(tài),不消耗事件,Button默認為可點擊狀態(tài),消耗事件。
備注:控件不可點擊時,在執(zhí)行到onTouchEvent方法時,無法進入手勢的判斷邏輯,所以會return false,反之,View可點擊必然return true;

分析源碼得知,如果一個View是可點擊的,則onTouchEvent會 return true, 由此dispatchTouchEvent也會返回true,即消耗了事件。


可重寫ViewGroup的onInterceptTouchEvent或者調(diào)用requestDisallowInterceptTouchEvent ?對事件進行攔截。
?? ?但在ViewGroup 的dispatchTouchEvent中接收到ACTION_DOWN 事件時,會重置所有狀態(tài),所以注意requestDisallowInterceptTouchEvent的調(diào)用時機。

舉個栗子,可以在子View的onTouchEvent中調(diào)用(此種情景一般是在一個可橫向滑動的組件中,嵌套了另一個橫向滑動的組件,比如ViewPager里面 存在一個可橫向滑動的view,可重寫此View,使其在橫向滾動的時候,不觸發(fā)ViewPager的翻頁效果)

挖坑~!~!~!~
1>在重寫onInterceptTouchEvent 的時候要注意 return true或 false 的時機。
2>可以參考下ScrollView?onInterceptTouchEvent 寫法,代碼如下(精簡版)

?? ??? ?可以看到?onInterceptTouchEvent返回值 是由mIsBeingDragged 決定的,可以改變mIsBeingDragged值的幾個方地方 已經(jīng)用箭頭標志出來,action_down事件時一般情況下會返回false(例外:Scrollview 處于滾動時會返回true),所以down事件一般不會對事件進行攔截。
? ? ? ? ? 那攔截事件的邏輯就到了action_move中,可以簡單理解為手指移動一定距離之后,ScrollView就會攔截事件,這樣做的好處就是,在未達到滑動的距離的時候,事件可以傳遞到子View(如果沒有這個操作,我們也就無法在子View中調(diào)用requestDisallowInterceptTouchEvent 來請求父類 放開的屬于自己的事件了)。
當action_down事件到達view時,假如view的dispatchTouchEvent返回false ,則后續(xù)的action_up、action_move等不會再到達View.
分析:
1、ACTION_DOWN事件到達ViewGroup之后 通過dispatchTouchEvent分發(fā)至View.
2、如View的dispatchTouchEvent返回true則表示View消耗了事件,此時ViewGroup 會記錄下此View(源碼中使用mFirstTouchTarget記錄,可以看下 下面的源碼 ).
3、當后續(xù)事件到達時,會先判斷是否記錄了消耗事件的View,如記錄了則繼續(xù)調(diào)用View的dispatchTouchEvent進行事件的分發(fā)。
4、反之View的dispatchTouchEvent 返回false ,表示View不消耗事件,ViewGroup 不對此View 進行記錄,后續(xù)事件到達時,判斷沒有記錄任何View,會執(zhí)行super.dispatchTouchEvent(event)(ViewGroup 繼承了view,此處實際執(zhí)行的是父view的dispatchTouchEvent).

View中 有dispatchTouchEvent,onTouchEvent。
ViewGroup 有dispatchTouchEvent,onTouchEvent 、onInterceptTouchEvent 。
事件的分發(fā)傳遞機制 核心就是這三兩個方法,個人理解:
1、對于ViewGroup中的dispatchTouchEvent主要是用來分發(fā)事件的,找到消耗事件的View,將事件傳遞給它(其實就是調(diào)用View的dispatchTouchEvent),然后根據(jù) 返回值,來判斷此次事件已結(jié)束(return true)還是調(diào)用自己父View中的dispatchTouchEvent(return false)由自己來消耗事件。
2、對于View,dispatchTouchEvent、onTouchEvent 簡單說 就是為了 消耗事件(處理事件),但消耗與否 ,由自身的一些屬性決定
? ?1> 在dispatchTouchEvent中如果OnTouchListener 不為空,View enable同時?OnTouchListener.onTouch() 為true,則 ?dispatchTouchEvent return true 消耗了此次事件。
? ? ? ? ?多說一句,此時,dispatchTouchEvent后續(xù)代碼不會執(zhí)行,導致onTouchEvent不會被執(zhí)行,onClick是在onTouchEvent中被調(diào)用,所以此種情況下,onClick回調(diào)無效。
? ?2> 如果不符合情況1,此時,會執(zhí)行dispatchTouchEvent后續(xù)代碼,即會調(diào)用onTouchEvent,在前面也介紹過,View可點擊時 ,會消耗事件(如Button),不可點擊時,不消耗事件(如TextView,ImageView)
補充:
Activity的dispatchTouchEvent
? 代碼很少,很好理解,在activity的dispatchTouchEvent的中首先調(diào)用了PhoneWindow的superDispatchTouchEvent ,然后巴拉巴拉巴拉~!~!~ 還是看下面的源碼吧,找到最后,發(fā)現(xiàn)是調(diào)用了ViewGroup的dispatchTouchEvent,這樣從源碼上也可以看出,分發(fā)的流程就是Activity->ViewGroup->View了。
????????getWindow().superDispatchTouchEvent(ev) 如為false,則 沒有ViewGroup 或者view消耗事件,最終會調(diào)用Activity的onTouchEvent,由Activity自身處理事件。



