view的事件分發機制不僅僅是核心知識點更是難點,當view遇到滑動沖突或者其他沖突事件的時候,它的解決方法的理論基礎就是事件分發機制,這章就來學習下view的事件分發機制
在了解分發機制之前,我們需要了解下一個對象,MotionEvent,就是一系列的監聽view的狀態的對象,其實點擊事件的分發,就是MotionEvent的分發過程,當一個MontionEvent對象產生之后,系統需要把這個事件傳遞給一個具體的view,這個傳遞的過程就是分發過程,它有三個很重要的方法組成:dispatchTouchEvent,onIntercepTouchEvent和onTouchEvent,下面來介紹下這三個方法
dispatchTouchEvent
用于進行事件的分發,如果事件能夠傳遞給當前的view,那么這個方法一定會被調用,返回的結果受當前view的onTouchEvent和下級view的dispatchTouchEvent方法的影響,返回true,則由當前view進行事件處理,則當前view的onTouchEvent方法會被調用,false則往下分發,注意的是,如果當前的view是頂級view,則由Activity處理,如果不是頂級view,則由頂級view去處理,默認情況下會由當前的view處理
onIntercepTouchEvent
用來判斷是否攔截某個事件,true表示攔截,false表示不攔截,如果當前的view攔截了某個事件,那么在同個事件序列之中,則不會再次調用此方法,也就是說,如果我攔截了滑動事件,那么當再有滑動事件的時候,這個方法不會再次被調用,自動攔截,不攔截事件的話,則會繼續往下傳遞,默認情況下會攔截,由當前的view處理
onTouchEvent
用來處理事件,在dispatchTouchEvent方法中調用,返回結果是否處理當前事件,如果不處理,則在同個事件的序列中,當前的view無法再次接受到該事件,如果返回true,則處理該事件,如果返回false,則事件會從當前的view往上傳遞,默認情況下會處理事件,如果都不處理該事件,那該事件則會“消失”,并且接受不到下一次事件
三者關系
我們知道這三個方法是干嘛用之后,我們來看看他們的關系,假設現在有個xml布局,里面只有一個Button,我們給Button添加點擊事件,那么當點擊事件發生之后,首先會傳遞到頂層view,這時候頂view(也叫根ViewGroup)的dispatchTouchEvent方法就會被調用,由它來決定事件的分發,如果頂view的onIntercepTouchEvent返回true,則表示它要攔截這個點擊事件,就不會再往下傳遞,就交給了它的onTouchEvent方法處理;如果是false,則表示它不攔截這個點擊事件,就繼續往下傳遞,到達它的子view,然后子view的dispatchTouchEvent方法被調用,然后繼續判斷是否需要進行事件分發,以此類推下去
這里要注意的地方有兩個:
1,如果我們的view設置了onTouchListener之后,那么onTouchListener中的onTouch方法會優先被調用,這時候的事件處理還得看onTouch的返回結果,如果是false,則當前view的onTouchEvent直接就被調用了,true則不會被調用,在像上面那樣進行分發,由此可見,onTouchListener的優先級比onTouchEvent要高
2,當一個view的事件觸發后,它傳遞的過程是:Activity——>Window——>頂層view,頂層view接受到事件后,就會根據事件分發機制去傳遞,如果所有的view都不處理這個事件,那么這個事件就會傳遞回給Activity,Activity的onTouchEvent的方法會被調用,這個過程很好理解,舉個簡單的例子,假如點擊事件是個任務,這個任務由項目經理安排下來給某個程序員做(這個就相當于事件分發),結果這個程序員搞不得(onTouchEvent返回false),那怎么辦?任務得完成啊,難題得解決,這時候就需要能力強的程序員出馬了(上級的onTouchEvent被調用),如果還是不行,就一級一級往上推,最后都不行的話,那就只能項目經理出馬了,如果項目經理也搞不得,改需求吧~~~
總結
1,同個事件順序是從手指觸摸屏幕那一刻開始,到手指離開屏幕那一刻結束
2,正常情況下,一個事件只能被一個view攔截,因為一旦一個view攔截了某個事件,那么同個事件序列都會直接交給它處理,但也可以通過特殊手段處理,比如view可以將本應該是自己處理的事件再通過onTouchEvent強行傳遞給其他view處理
3,view一旦攔截某個事件后,onIntercepTouchEvent不會再次被調用,也就是說系統不會再去詢問它是否還要攔截,而是直接就交個它處理,這里注意的是,必須是同個事件,而不是說我攔截了點擊事件,然后會自動攔截其他事件
4,view一旦攔截某個事件后,必須處理掉該事件,否則當有事件來的時候,會重新由頂view重新分發,比如說項目經理交個你任務,你還沒做完,那么項目經理不會再將其他任務交給你
5,默認不攔截任何事件下,onIntercepTouchEvent默認返回false
6,如果view沒有onIntercepTouchEvent方法,一旦有點擊事件傳遞給它,它的onTouchEvent方法會被調用
7,view的onTouchEvent方法默認會處理掉事件(返回true),除非它不可以點擊(clickable和longClickable都是false),默認情況下,view的longClickable返回false,clickable屬性要分情況,比如Button默認的是true,TextView默認是false
8,view的enable屬性不會影響onTouchEvent默認的返回值,只要它的clickable或者longClickable有一個是true,那么它的onTouchEvent默認就是返回true
9,事件傳遞過程是由外向內傳遞,總是先從頂view開始,一級一級往下傳遞
好了,這篇文章就先簡單介紹下事件分發機制,下篇在深入去了解