自定義View事件的分發(fā)及傳遞機制

一丶? 一個完整的事件傳遞機制? 必定包含三種事件: 由一個 down 事件、 多 個 move 事件,一個 up 事件組成(還有一個cancel事件,該事件是在被上層攔截時觸發(fā))。

手指落下(ACTION_DOWN) -> 移動(ACTION_MOVE) -> 離開(ACTION_UP) ?

二丶Touch一般的傳遞流程:Activity------>window(唯一實現(xiàn)類是PhoneWindow)------>頂級View(DecorView)------>ViewGroup------>View? ? ;(可概括為一句話:責任鏈模式,事件層層傳遞,直到被消費)



三丶監(jiān)聽Touch事件的兩種方式:setTouchListener和直接重寫三個方法:dispatchToucEvent,?onInterceptTouchEvent, ?onTouchEvent.


1.setTouchListener:

此方法監(jiān)聽的優(yōu)先級比較高,如果在onTouchListener的onTouch方法里面執(zhí)行了return true,那么說明消費了該事件 ,而OnTouchEvent是接收不到該事件的,因此在onClickListener里面的Onclick方法是執(zhí)行不到的,因為Onclick是在OnTouchEvent種被調用的,因此Touch事件走不到OnTouchEvent事件的話,Onclick方法是不會被執(zhí)行的.

2,dispatchToucEvent:

為什么ViewGroupdispatchToucEvent,View 也有dispatchToucEvent,是因為View 可以注冊很多事件監(jiān)聽器,例如:單擊事件(onClick)、長按事件(onLongClick)、觸摸事件(onTouch),并且View自身也有 onTouchEvent 方法,那么問題來了,這么多與事件相關的方法應該由誰管理?就是dispatchTouchEvent.()

那么,這么多的事件,他們的事件調度順序是怎樣的呢?

從源碼的角度去分析:?

從設計的角度去分析:

1).單擊事件(onClickListener) 需要兩個兩個事件(ACTION_DOWN 和 ACTION_UP )才能觸發(fā),如果先分配給onClick判斷,等它判斷完,用戶手指已經(jīng)離開屏幕了,定然造成 View 無法響應其他事件,應該最后調用。(最后)

2).長按事件(onLongClickListener) 同理,也是需要長時間等待才能出結果,肯定不能排到前面,但因為不需要ACTION_UP,應該排在 onClick 前面。(onLongClickListener > onClickListener)

3).觸摸事件(onTouchListener) 如果用戶注冊了觸摸事件,說明用戶要自己處理觸摸事件了,這個應該排在最前面。(最前)

4).View自身處理(onTouchEvent) 提供了一種默認的處理方式,如果用戶已經(jīng)處理好了,也就不需要了,所以應該排在 onTouchListener 后面。(onTouchListener > onTouchEvent)


由上可以推導出來:

事件的調度順序應該是onTouchListener > onTouchEvent > onLongClickListener > onClickListener。


舉個栗子:


LinearLayout這里設置了點擊一個事件,然后在執(zhí)行的時候你會發(fā)現(xiàn)怎么點擊都不會接收到消息,這是因為View這里設置了clickble的屬性為true.也就是這個事件被孩子吃掉了.那么父親是不會再走TouchEvent的

3.onInterceptTouchEvent:

這個是ViewGroup專有的,該事件在ViewGroup一層一層傳遞的,最終傳遞給 View,ViewGroup 要比它的 ChildView 先拿到事件,并且有權決定是否告訴要告訴 ChildView。

一般情況下,該事件在ViewGroup中是這樣分發(fā)的:

1.判斷自身是否需要(詢問 onInterceptTouchEvent 是否攔截),如果需要,調用自己的 onTouchEvent。

2.自身不需要或者不確定,則詢問 ChildView ,一般來說是調用手指觸摸位置的 ChildView。

3.如果子 ChildView 不需要則調用自身的 onTouchEvent。

ViewGroup通過遍歷ChildView,確定手指點在哪個ChildView的區(qū)域內,然后將事件發(fā)放到該ChildView,而當ChildView存在覆蓋的情況時,ViewGroup會將事件分發(fā)到最上層的ChildView上(一般后加載的CHildView是會覆蓋前面加載了的,所以最上層的是最后加載的)



當手指點擊有重疊區(qū)域時,分如下幾種情況:

只有 View1 可點擊時,事件將會分配給 View1,即使被 View2 遮擋,這一部分仍是 View1 的可點擊區(qū)域。

只有 View2 可點擊時,事件將會分配給 View2。

View1 和 View2 均可點擊時,事件會分配給后加載的 View2,View2 將事件消費掉,View1接收不到事件。

注意:

上面說的是可點擊,可點擊包括很多種情況,只要你給View注冊了onClickListener、onLongClickListener、OnContextClickListener其中的任何一個監(jiān)聽器或者設置了android:clickable=”true”就代表這個 View 是可點擊的。

另外,某些 View 默認就是可點擊的,例如,Button,CheckBox 等。

給 View 注冊 OnTouchListener 不會影響 View 的可點擊狀態(tài)。即使給 View 注冊 OnTouchListener ,只要不返回 true 就不會消費事件。

3. ViewGroup 和 ChildView 同時注冊了事件監(jiān)聽器(onClick等),哪個會執(zhí)行?

事件優(yōu)先給 ChildView,會被 ChildView消費掉,ViewGroup 不會響應。

4. 所有事件都應該被同一 View 消費

在上面的例子中我們分析后可以了解到,同一次點擊事件只能被一個 View 消費,主要是為了防止事件響應混亂,如果再一次完整的事件中分別將不同的事件分配給了不同的 View 容易造成事件響應混亂。

View 中 onClick 事件需要同時接收到 ACTION_DOWN 和 ACTION_UP 才能觸發(fā),如果分配給了不同的 View,那么 onClick 將無法被正確觸發(fā)。

安卓為了保證所有的事件都是被一個 View 消費的,對第一次的事件( ACTION_DOWN )進行了特殊判斷,View 只有消費了 ACTION_DOWN 事件,才能接收到后續(xù)的事件(可點擊控件會默認消費所有事件),并且會將后續(xù)所有事件傳遞過來,不會再傳遞給其他 View,除非上層 View 進行了攔截。

如果上層 View 攔截了當前正在處理的事件,會收到一個 ACTION_CANCEL,表示當前事件已經(jīng)結束,后續(xù)事件不會再傳遞過來。(詳細細節(jié)可以查看源碼~~~~)

核心要點(重點!!!!)

事件分發(fā)原理: 責任鏈模式,事件層層傳遞,直到被消費。

View 的dispatchTouchEvent主要用于調度自身的監(jiān)聽器和 onTouchEvent。

View的事件的調度順序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener 。

不論 View 自身是否注冊點擊事件,只要 View 是可點擊的就會消費事件。

事件是否被消費由返回值決定,true 表示消費,false 表示不消費,與是否使用了事件無關。

ViewGroup 中可能有多個 ChildView 時,將事件分配給包含點擊位置的 ChildView。

ViewGroup 和 ChildView 同時注冊了事件監(jiān)聽器(onClick等),由 ChildView 消費。

一次觸摸流程中產生事件應被同一 View 消費,全部接收或者全部拒絕。

只要接受 ACTION_DOWN 就意味著接受所有的事件,拒絕 ACTION_DOWN 則不會收到后續(xù)內容。

如果當前正在處理的事件被上層 View 攔截,會收到一個 ACTION_CANCEL,后續(xù)事件不會再傳遞過來。


最后附一張示意圖:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內容