ps: 需要具體源碼分析的童鞋可以轉(zhuǎn)戰(zhàn)原文博客吠裆,內(nèi)容十分詳盡旱捧,此文為摘錄原文結(jié)論部分撒踪,簡(jiǎn)明非扼要。
Activity中觸摸事件
相關(guān)API:
- dispatchTouchEvent()和onTouchEvent()
總結(jié):
Activity中的dispatchTouchEvent會(huì)將觸摸事件傳遞給Activity所包含的視圖浪讳。具體的實(shí)現(xiàn)方式在通過(guò)調(diào)用到Activity所屬Window的superDispatchTouchEvent,進(jìn)而調(diào)用到Window的DecorView的superDispatchTouchEvent涌萤,進(jìn)一步的又調(diào)用到ViewGroup的dispatchTouchEvent()淹遵。如果Activity所包含的視圖攔截或者消費(fèi)了該觸摸事件的話(huà),就不會(huì)再執(zhí)行Activity的onTouchEvent()负溪;如果Activity所包含的視圖沒(méi)有攔截或者消費(fèi)該觸摸事件的話(huà)透揣,則會(huì)執(zhí)行Activity的onTouchEvent()。
Activity中的onTouchEvent是Activity自身對(duì)觸摸事件的處理川抡。如果該Activity的android:windowCloseOnTouchOutside屬性為true辐真,并且當(dāng)前觸摸事件是ACTION_DOWN,而且該觸摸事件的坐標(biāo)在Activity之外崖堤,同時(shí)Activity還包含了視圖的話(huà)侍咱;就會(huì)導(dǎo)致Activity被結(jié)束。
View中觸摸事件
相關(guān)API:
dispatchTouchEvent()和onTouchEvent()
OnTouchListener, OnClickListener, OnLongClickListener等接口
總結(jié):
View中的dispatchTouchEvent()會(huì)將事件傳遞給"自己的onTouch()", "自己的onTouchEvent()"進(jìn)行處理密幔。而且onTouch()的優(yōu)先級(jí)比onTouchEvent()的優(yōu)先級(jí)要高楔脯。
onTouch()與onTouchEvent()都是View中用戶(hù)處理觸摸事件的API。onTouch是OnTouchListener接口中的函數(shù)胯甩,OnTouchListener接口需要用戶(hù)自己實(shí)現(xiàn)淤年。onTouchEvent()是View自帶的接口,Android系統(tǒng)提供了默認(rèn)的實(shí)現(xiàn)蜡豹;當(dāng)然麸粮,用戶(hù)可以重載該API。
onTouch()與onTouchEvent()有兩個(gè)不同之處:
onTouch()是View提供給用戶(hù)镜廉,讓用戶(hù)自己處理觸摸事件的接口弄诲。而onTouchEvent()是Android系統(tǒng)自己實(shí)現(xiàn)的接口。
onTouch()的優(yōu)先級(jí)比onTouchEvent()的優(yōu)先級(jí)更高娇唯。dispatchTouchEvent()中分發(fā)事件的時(shí)候齐遵,會(huì)先將事件分配給onTouch()進(jìn)行處理,然后才分配給onTouchEvent()進(jìn)行處理塔插。 如果onTouch()對(duì)觸摸事件進(jìn)行了處理梗摇,并且返回true;那么想许,該觸摸事件就不會(huì)分配在分配給onTouchEvent()進(jìn)行處理了伶授。只有當(dāng)onTouch()沒(méi)有處理断序,或者處理了但返回false時(shí),才會(huì)分配給onTouchEvent()進(jìn)行處理糜烹。
ViewGroup中觸摸事件
ViewGroup繼承于View违诗,它中對(duì)觸摸事件的處理,很多都繼承于View疮蹦。但是诸迟,ViewGroup又有自己對(duì)觸摸事件的特定處理.
相關(guān)API:
ViewGroup重載了dispatchTouchEvent()接口。
ViewGroup新增了onInterceptTouchEvent()接口愕乎。
總結(jié):
ViewGroup中的dispatchTouchEvent()會(huì)將觸摸事件進(jìn)行遞歸遍歷傳遞阵苇。ViewGroup會(huì)遍歷它的所有孩子,對(duì)每個(gè)孩子都遞歸的調(diào)用dispatchTouchEvent()來(lái)分發(fā)觸摸事件感论。
如果ViewGroup的某個(gè)孩子沒(méi)有接受(消費(fèi)或者攔截)ACTION_DOWN事件绅项;那么,ACTION_MOVE和ACTION_UP等事件也一定不會(huì)分發(fā)給這個(gè)孩子笛粘!
ViewGroup的onInterceptTouchEvent()默認(rèn)返回false趁怔。
ViewGroup沒(méi)有覆蓋onTouchEvent()。因此薪前,調(diào)用ViewGroup的onTouchEvent()的話(huà)润努;實(shí)際上調(diào)用的是它的父類(lèi)View的onTouchEvent()。
事件分發(fā)案例
??默認(rèn)分發(fā)觸摸事件??
定義:
自定義一個(gè)Activity示括,該Activity中的顯示內(nèi)容是包含一個(gè)自定義的ViewGroup铺浇,該ViewGroup中包含一個(gè)自定義的View。
- 自定義的Activity-MyActivity
public boolean dispatchTouchEvent(MotionEvent ev): 調(diào)用系統(tǒng)默認(rèn)的dispatchTouchEvent()
public boolean onTouchEvent(MotionEvent ev): 調(diào)用系統(tǒng)默認(rèn)的onTouchEvent()
- 自定義ViewGroup-MyViewGroup
public boolean dispatchTouchEvent(MotionEvent ev): 調(diào)用系統(tǒng)默認(rèn)的dispatchTouchEvent()
public boolean onTouchEvent(MotionEvent ev): 調(diào)用系統(tǒng)默認(rèn)的onTouchEvent()
public boolean onInterceptTouchEvent(MotionEvent ev):: 調(diào)用系統(tǒng)默認(rèn)的onInterceptTouchEvent()
- 自定義View-MyView
public boolean dispatchTouchEvent(MotionEvent ev): 調(diào)用系統(tǒng)默認(rèn)的dispatchTouchEvent()
public boolean onTouchEvent(MotionEvent ev): 調(diào)用系統(tǒng)默認(rèn)的onTouchEvent()
處理流程圖:

測(cè)試流程:
MyActivity收到ACTION_DOWN垛膝,進(jìn)入MyActivity.dispatchTouchEvent()鳍侣。
MyActivity.dispatchTouchEvent()對(duì)ACTION_DOWN觸摸事件進(jìn)行分發(fā),將消息傳遞給MyViewGroup吼拥。即倚聚,進(jìn)入MyViewGroup.dispatchTouchEvent()。
MyViewGroup.dispatchTouchEvent()會(huì)調(diào)用MyViewGroup.onInterceptTouchEvent()檢查自己有沒(méi)有對(duì)觸摸事件進(jìn)行攔截凿可。即先進(jìn)入MyViewGroup.onInterceptTouchEvent()惑折。
緊接著,MyViewGroup會(huì)退出MyViewGroup.onInterceptTouchEvent()枯跑。因?yàn)镸yViewGroup沒(méi)有對(duì)觸摸事件進(jìn)行攔截惨驶,MyViewGroup會(huì)繼續(xù)分發(fā)事件。
MyViewGroup將觸摸事件分發(fā)給MyView敛助,即進(jìn)入MyView.dispatchTouchEvent()粗卜。
MyView會(huì)調(diào)用onTouchEvent()對(duì)觸摸事件進(jìn)行處理,即進(jìn)入MyView.onTouchEvent() 纳击。
緊接著续扔,MyView會(huì)退出MyView.onTouchEvent()攻臀。返回false給MyView.dispatchTouchEvent()。
MyView收到MyView.onTouchEvent()的返回值之后测砂,退出MyView.dispatchTouchEvent()茵烈。返回false給MyViewGroup的MyViewGroup.dispatchTouchEvent()百匆,表示MyView沒(méi)有接受該觸摸事件砌些。
MyViewGroup則得知MyView沒(méi)有接受該觸摸事件之后,將自己當(dāng)作一個(gè)View加匈,調(diào)用View.dispatchTouchEvent()存璃;View.dispatchTouchEvent()接著就會(huì)進(jìn)入MyViewGroup.onTouchEvent()。
緊接著雕拼,就會(huì)退出MyViewGroup.onTouchEvent()纵东。MyViewGroup.onTouchEvent()沒(méi)有消費(fèi)該觸摸事件,因此返回false啥寇。
然后偎球,View.dispatchTouchEvent()就會(huì)結(jié)束,并返回false辑甜。接著衰絮,MyViewGroup就會(huì)退出MyViewGroup.dispatchTouchEvent()。并返回false磷醋。
MyActivity在得知MyViewGroup沒(méi)有接受該觸摸事件之后猫牡,就會(huì)調(diào)用進(jìn)入MyActivity.onTouchEvent。
緊接著邓线,就會(huì)退出MyActivity.onTouchEvent淌友,并返回false。
至此骇陈,MyActivity.dispatchTouchEvent()才結(jié)束震庭。因此,會(huì)退出MyActivity.dispatchTouchEvent()你雌,并返回false器联。
??View接受觸摸事件??
定義:
MyView onTouchEvent() 函數(shù)返回true,其余處理同默認(rèn)分發(fā)觸摸事件匪蝙。
處理流程圖:

測(cè)試流程
MyActivity收到ACTION_DOWN主籍,進(jìn)入MyActivity.dispatchTouchEvent()。
MyActivity.dispatchTouchEvent()對(duì)ACTION_DOWN觸摸事件進(jìn)行分發(fā)逛球,將消息傳遞給MyViewGroup千元。即,進(jìn)入MyViewGroup.dispatchTouchEvent()颤绕。
MyViewGroup.dispatchTouchEvent()會(huì)調(diào)用MyViewGroup.onInterceptTouchEvent()檢查自己有沒(méi)有對(duì)觸摸事件進(jìn)行攔截幸海。即先進(jìn)入MyViewGroup.onInterceptTouchEvent()祟身。 (04) 緊接著,MyViewGroup會(huì)退出MyViewGroup.onInterceptTouchEvent()物独。因?yàn)镸yViewGroup沒(méi)有對(duì)觸摸事件進(jìn)行攔截袜硫,MyViewGroup會(huì)繼續(xù)分發(fā)事件.
MyViewGroup將觸摸事件分發(fā)給MyView,即進(jìn)入MyView.dispatchTouchEvent()挡篓。
MyView會(huì)調(diào)用onTouchEvent()對(duì)觸摸事件進(jìn)行處理婉陷,即進(jìn)入MyView.onTouchEvent() 。 (07) 緊接著官研,MyView會(huì)退出MyView.onTouchEvent()秽澳。此時(shí)的,MyView.onTouchEvent()返回的是true戏羽;表示MyView消費(fèi)了此次觸摸事件担神。
MyView.dispatchTouchEvent()得知MyView.onTouchEvent()消費(fèi)此次觸摸事件之后;也就返回true始花,表示MyView接受該此次觸摸事件妄讯。
MyViewGroup則得知MyView接受了該觸摸事件之后,就退出MyViewGroup.dispatchTouchEvent()酷宵,并返回true亥贸。
MyActivity得知MyViewGroup接受了該觸摸事件之后,就會(huì)調(diào)用退出MyActivity.dispatchTouchEvent()忧吟,并返回true砌函。
結(jié)論:
如果MyView接受了ACTION_DOWN,那么就不會(huì)再再執(zhí)行其他對(duì)象的onTouchEvent()函數(shù)的溜族。即讹俊,不會(huì)執(zhí)行MyViewGroup的onTouchEvent()和MyActivity的onTouchEvent()。因?yàn)镸yView接受了ACTION_DOWN煌抒,意味著這個(gè)事件已經(jīng)被消費(fèi)了仍劈;就無(wú)須其他對(duì)象再來(lái)消費(fèi)ACTION_DOWN了。
如果MyView接受了ACTION_DOWN寡壮,那么MyView能繼續(xù)收到ACTION_MOVE和ACTION_UP這兩種觸摸觸事件贩疙。并且ACTION_MOVE和ACTION_UP的處理流程和ACTION_DOWN的流程基本一樣。
??ViewGroup攔截但不消費(fèi)觸摸事件??
定義:
MyViewGroup onInterceptTouchEvent() 函數(shù)返回true况既,其余處理同默認(rèn)分發(fā)觸摸事件这溅。
處理流程圖:

測(cè)試流程
MyActivity收到ACTION_DOWN,進(jìn)入MyActivity.dispatchTouchEvent()棒仍。
MyActivity.dispatchTouchEvent()對(duì)ACTION_DOWN觸摸事件進(jìn)行分發(fā)悲靴,將消息傳遞給MyViewGroup。即莫其,進(jìn)入MyViewGroup.dispatchTouchEvent()癞尚。
MyViewGroup.dispatchTouchEvent()會(huì)調(diào)用MyViewGroup.onInterceptTouchEvent()檢查自己有沒(méi)有對(duì)觸摸事件進(jìn)行攔截耸三。即先進(jìn)入MyViewGroup.onInterceptTouchEvent()。
緊接著浇揩,MyViewGroup會(huì)退出MyViewGroup.onInterceptTouchEvent()仪壮。此時(shí),MyViewGroup.onInterceptTouchEvent()返回true胳徽。表示MyViewGroup攔截了該觸摸事件积锅。
MyViewGroup在得知自己攔截了觸摸事件之后,將觸摸事件交給自己的onTouchEvent()進(jìn)行處理膜廊,即進(jìn)入MyViewGroup.onTouchEvent()乏沸。
緊接著淫茵,MyViewGroup會(huì)退出MyViewGroup.onTouchEvent()爪瓜。而MyViewGroup自身并沒(méi)有消費(fèi)該事件,因此MyViewGroup.onTouchEvent()返回false匙瘪。
隨后铆铆,退出MyViewGroup.dispatchTouchEvent(),并返回false丹喻。表示MyViewGroup沒(méi)有接受該觸摸事件薄货。
MyActivity得知MyViewGroup沒(méi)有接受該觸摸事件之后,就會(huì)調(diào)用進(jìn)入MyActivity.onTouchEvent()碍论。
緊接著谅猾,MyActivity會(huì)退出MyActivity.onTouchEvent(),并返回false鳍悠。表示MyActivity也沒(méi)有消費(fèi)觸摸事件税娜。
最后满粗,MyActivity會(huì)退出MyActivity.dispatchTouchEvent()颤专,并返回false。表示此次觸摸事件沒(méi)有被消費(fèi)盖呼。
結(jié)論:
MyViewGroup攔截了ACTION_DOWN蠢挡,并沒(méi)有消費(fèi)該ACTION_DOWN弧岳。既然MyViewGroup攔截了ACTION_DOWN,那就意味著該事件就不會(huì)分發(fā)給MyViewGroup的子類(lèi)业踏。但是由于MyViewGroup沒(méi)有消費(fèi)該事件禽炬,即它并沒(méi)有接受該事件;那么勤家,ACTION_DOWN會(huì)繼續(xù)查找其他對(duì)象來(lái)消費(fèi)它自己腹尖,這也意味著該觸摸事件仍然會(huì)發(fā)送MyActivity的onTouchEvent()。如果MyActivity中有和MyViewGroup同級(jí)別的GroupView的話(huà)却紧,在得知MyViewGroup攔截了ACTION_DOWN桐臊,卻沒(méi)有消費(fèi)該ACTION_DOWN之后胎撤;MyActivity仍然能夠向這個(gè)同級(jí)的GroupView分發(fā)消息。
MyViewGroup并沒(méi)有消費(fèi)ACTION_DOWN断凶,那么伤提,MyViewGroup就不能接受到ACTION_MOVE和ACTION_UP這兩種觸摸觸事件。至于MyViewGroup的子類(lèi)MyView认烁,就更加不可能接受到ACTION_MOVE和ACTION_UP了肿男。
??ViewGroup攔截并消費(fèi)觸摸事件??
定義:
MyViewGroup onInterceptTouchEvent() 函數(shù)返回true; MyViewGroup onTouchEvent()返回true; 其余處理同默認(rèn)分發(fā)觸摸事件。
處理流程圖:

測(cè)試流程
MyActivity收到ACTION_DOWN却嗡,進(jìn)入MyActivity.dispatchTouchEvent()舶沛。
MyActivity.dispatchTouchEvent()對(duì)ACTION_DOWN觸摸事件進(jìn)行分發(fā),將消息傳遞給MyViewGroup窗价。即如庭,進(jìn)入MyViewGroup.dispatchTouchEvent()。
MyViewGroup.dispatchTouchEvent()會(huì)調(diào)用MyViewGroup.onInterceptTouchEvent()檢查自己有沒(méi)有對(duì)觸摸事件進(jìn)行攔截撼港。即先進(jìn)入MyViewGroup.onInterceptTouchEvent()坪它。
緊接著,MyViewGroup會(huì)退出MyViewGroup.onInterceptTouchEvent()帝牡。此時(shí)往毡,MyViewGroup.onInterceptTouchEvent()返回true。表示MyViewGroup攔截了該觸摸事件靶溜。
MyViewGroup在得知自己攔截了觸摸事件之后开瞭,將觸摸事件交給自己的onTouchEvent()進(jìn)行處理,即進(jìn)入MyViewGroup.onTouchEvent()罩息。
緊接著嗤详,MyViewGroup會(huì)退出MyViewGroup.onTouchEvent(),并返回true扣汪。表示MyViewGroup消費(fèi)了該事件断楷。
隨后,MyViewGroup會(huì)退出MyViewGroup.dispatchTouchEvent()崭别,并返回true冬筒。表示MyViewGroup接受了該觸摸事件。
MyActivity得知MyViewGroup接受了該觸摸事件之后茅主,就會(huì)退出MyActivity.dispatchTouchEvent()舞痰,并返回true。表示此次觸摸事件被消費(fèi)了
結(jié)論:
MyViewGroup攔截并消費(fèi)了ACTION_DOWN诀姚。那么响牛,該事件就不會(huì)分發(fā)給MyViewGroup的子類(lèi),也不會(huì)調(diào)用MyActivity的onTouchEvent()。
MyViewGroup攔截并消費(fèi)了ACTION_DOWN呀打。那么矢赁,MyViewGroup就會(huì)接受到ACTION_MOVE和ACTION_UP這兩種觸摸觸事件。而且對(duì)于ACTION_MOVE和ACTION_UP事件贬丛,不會(huì)再執(zhí)行攔截操作撩银,即不會(huì)調(diào)用MyViewGroup.onInterceptTouchEvent();而是直接調(diào)用MyViewGroup.onTouchEvent()對(duì)事件進(jìn)行處理豺憔。
??ViewGroup沒(méi)攔截但是卻消費(fèi)了觸摸事件??
定義:
MyViewGroup onTouchEvent() 函數(shù)返回true, 其余處理同默認(rèn)分發(fā)觸摸事件额获。
處理流程圖:

測(cè)試流程
MyActivity收到ACTION_DOWN,進(jìn)入MyActivity.dispatchTouchEvent()恭应。
MyActivity.dispatchTouchEvent()對(duì)ACTION_DOWN觸摸事件進(jìn)行分發(fā)抄邀,將消息傳遞給MyViewGroup。即昼榛,進(jìn)入MyViewGroup.dispatchTouchEvent()境肾。
MyViewGroup.dispatchTouchEvent()會(huì)調(diào)用MyViewGroup.onInterceptTouchEvent()檢查自己有沒(méi)有對(duì)觸摸事件進(jìn)行攔截。即先進(jìn)入MyViewGroup.onInterceptTouchEvent()褒纲。 (04) 緊接著准夷,MyViewGroup會(huì)退出MyViewGroup.onInterceptTouchEvent()。此時(shí)莺掠,MyViewGroup.onInterceptTouchEvent()返回true。表示MyViewGroup攔截了該觸摸事件读宙。
MyViewGroup在得知自己攔截了觸摸事件之后彻秆,將觸摸事件交給自己的onTouchEvent()進(jìn)行處理,即進(jìn)入MyViewGroup.onTouchEvent()结闸。
緊接著唇兑,MyViewGroup會(huì)退出MyViewGroup.onTouchEvent(),并返回true桦锄。表示MyViewGroup消費(fèi)了該事件扎附。
隨后,MyViewGroup會(huì)退出MyViewGroup.dispatchTouchEvent()结耀,并返回true留夜。表示MyViewGroup接受了該觸摸事件。
MyActivity得知MyViewGroup接受了該觸摸事件之后图甜,就會(huì)退出MyActivity.dispatchTouchEvent()碍粥,并返回true。表示此次觸摸事件被消費(fèi)了
結(jié)論:
MyViewGroup沒(méi)有攔截卻消費(fèi)了ACTION_DOWN黑毅。由于MyViewGroup沒(méi)有攔截ACTION_DOWN嚼摩,因此,該事件會(huì)繼續(xù)分發(fā)給MyViewGroup的子類(lèi)MyView。由于MyViewGroup消費(fèi)了ACTION_DOWN枕面,因此該事件不會(huì)分發(fā)給MyActivity的onTouchEvent()愿卒。
MyViewGroup沒(méi)有攔截卻消費(fèi)了ACTION_DOWN。那么潮秘,MyViewGroup仍然可以接受到ACTION_MOVE和ACTION_UP這兩種觸摸觸事件掘猿。但是對(duì)于MyView而言,由于MyView沒(méi)有接受該事件唇跨;因此稠通,MyView不會(huì)收到ACTION_MOVE和ACTION_UP。