android 事件分發(fā)原理

事件分發(fā)在 android 中實在是太重要了,滑動沖突的前置基礎(chǔ)知識,滑動沖突不會處理,那么大部分頁面效果是寫不出來的,尤其是時下越來越多的聯(lián)合滑動的頁面效果,典型的就是 behavior 了,其他的像是典型的滑動控件嵌套沖突,左滑退出,列表側(cè)滑菜單,下拉刷新,上拉加載都是需要我們對 android 事件分發(fā)有深刻理解的。

事件分發(fā)誰來控制

android 的頁面結(jié)構(gòu)是這樣的,典型的樹形結(jié)構(gòu)


頁面結(jié)構(gòu)圖1
頁面結(jié)構(gòu)圖2

每一個 Actvity 都有一個 window ,window 所有視圖的最頂層容器,視圖的外觀和行為都?xì)w他管,不論是背景顯示,標(biāo)題欄還是事件處理都是他管理。

一般我們用不到去操作 window ,但是觸控事件的接收和分發(fā)是由 window 來執(zhí)行的,window 會根據(jù)視圖樹的順序,從外向里層層傳遞觸控事件

所以觸控事件是由 window 接收并分發(fā)的。

事件分發(fā)4大方法

  • dispatchTouchEvent 事件分發(fā)
  • onInterceptTouchEvent 事件攔截
  • onTouchEvent 事件處理
  • requestDisallowInterceptTouchEvent(true)

ViewGroup 4個方法都有,View 沒有事件攔截方法。這4個方法就是 Android 事件分發(fā)和處理的具體方法了,我們在實際處理時都是重寫這4個方法。

這3個方法都有一個 boolean 的返回值,onInterceptTouchEvent 方法表示我要攔截這個事件,onTouchEvent 表示我處理了事件

  1. dispatchTouchEvent
    dispatchTouchEvent 方法作為 view 的事件處理的 API 入口,內(nèi)部會調(diào)用 onInterceptTouchEvent 和 onTouchEvent 來計算返回的 boolean 值,一般我們都不會動 dispatchTouchEvent 方法,因為沒有意思。但是我們直接返回 true 時,表示我消費這個事件了

  2. onInterceptTouchEvent
    onInterceptTouchEvent 方法默認(rèn)是返回 false 的,表示不會攔截這個事件,但是若是返回 true 則表示這個事件我攔截住了,就不再往我下一級 view 傳遞了,然后會把事件交給自己的 onTouchEvent 方法

  3. onTouchEvent
    onTouchEvent 方法可以獲取具體的觸控參數(shù),進行手勢方向,當(dāng)前手勢類型判斷,可以記錄觸摸點的 x,y 坐標(biāo)。onTouchEvent 方法若是返回 true ,則表示這個事件我已經(jīng)處理過了,那么整個事件傳遞過程就結(jié)速了,否則的話這個事件會原路返回,去一級一級的跑上一層 view 的 onTouchEvent 方法,直到有人返回 true 或是沒有了。

  4. requestDisallowInterceptTouchEvent
    view.getParent().requestDisallowInterceptTouchEvent(true) ,可以讓內(nèi)層的 view 獲取到事件,而忽略上層視圖的攔截。true 表示接受事件,fasle 表示不接受事件。原理分析看這里:

事件分發(fā)的順序

總的來說,事件是由其父視圖向子視圖傳遞,按前面的圖來說是這樣。

Activity -> PhoneWindow -> DecorView -> ViewGroup -> ... -> View
  1. window 根據(jù)視圖樹順序,從外到內(nèi)遍歷所有的 view ,詢問每一個遍歷出來的 view 你要不要消費觸摸事件
  2. 每個 view 會跑自己的 dispatchTouchEvent 方法,判斷自己是否需要消費這個事件
  3. dispatchTouchEvent 方法首先會詢問 onInterceptTouchEvent 方法,是否要攔截這個事件。
  4. 若是攔截則會跑自己的 onTouchEvent 方法,若不攔截則會傳遞給下一級 view,調(diào)用下一級 view 的 dispatchTouchEvent 方法
  5. onTouchEvent 若是返回 true ,表示事件實際處理過了,那么整個事件傳遞在這個節(jié)點就結(jié)速了,不再傳遞了。若是返回 fasle,這個事件會原路返回,去一級一級的跑上一層 view 的 onTouchEvent 方法,直到有人返回 true 或是沒有了。
Snip20181023_27.png
005Xtdi2jw1f88i0q8uozj30nm0kqwhm.jpg
2157910-7d71eb5d5dff748e.png

這個點建議大家去看經(jīng)典的文章

前人的經(jīng)典文章我就不逾越了,推薦大家看經(jīng)典,省的理解錯誤,這里我放地址

具體的例子我就不寫了,大家看這篇文章的例子,設(shè)計的很全面

想了解的觸控類型和參數(shù)還有源碼分析的看這里

想更詳細(xì)了解 MotionEvent 看這里,很詳細(xì)包括多點觸控

我復(fù)制一下核心要點:

  • 事件分發(fā)原理: 責(zé)任鏈模式,事件層層傳遞,直到被消費。
  • View 的 dispatchTouchEvent 主要用于調(diào)度自身的監(jiān)聽器和 onTouchEvent。
  • View的事件的調(diào)度順序是 onTouchListener > onTouchEvent > onLongClickListener > onClickListener 。
  • 不論 View 自身是否注冊點擊事件,只要 View 是可點擊的就會消費事件。
  • 事件是否被消費由返回值決定,true 表示消費,false 表示不消費,與是否使用了事件無關(guān)。
  • ViewGroup 中可能有多個 ChildView 時,將事件分配給包含點擊位置的 ChildView。
  • ViewGroup 和 ChildView 同時注冊了事件監(jiān)聽器(onClick等),由 ChildView 消費。
  • 一次觸摸流程中產(chǎn)生事件應(yīng)被同一 View 消費,全部接收或者全部拒絕。
  • 只要接受 ACTION_DOWN 就意味著接受所有的事件,拒絕 ACTION_DOWN 則不會收到后內(nèi)容。
  • 如果當(dāng)前正在處理的事件被上層 View 攔截,會收到一個 ACTION_CANCEL,后續(xù)事件不會再傳遞過來。

參考資料:


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容