一婴洼、簡(jiǎn)介 :
????????Activity或View類的onTouchEvent()回調(diào)函數(shù)會(huì)接收到touch事件⊥沂欤
一個(gè)完整的手勢(shì)是從ACTION_DOWN開始摘投,到ACTION_UP結(jié)束。
簡(jiǎn)單的情況下懂傀,我們只需要在onTouchEvent()中寫個(gè)switch case語(yǔ)句趾诗,處理各種事件(Touch Down、 Touch Move蹬蚁、 Touch Up等)恃泪,但是比較復(fù)雜的動(dòng)作就需要更多的處理了。
????????ViewGroup作為一個(gè)parent是可以截獲傳向它的child的touch事件的缚忧。如果一個(gè)ViewGroup的onInterceptTouchEvent()方法返回true悟泵,說(shuō)明Touch事件被截獲,子View不再接收到Touch事件闪水,而是轉(zhuǎn)向本ViewGroup的 onTouchEvent()方法處理糕非。從Down開始,之后的Move球榆,Up都會(huì)直接在onTouchEvent()方法中處理朽肥。
先前還在處理touch event的child view將會(huì)接收到一個(gè) ACTION_CANCEL。如果onInterceptTouchEvent()返回false持钉,則事件會(huì)交給child view處理衡招。
????????Android中提供了ViewGroup、View每强、Activity三個(gè)層次的Touch事件處理始腾。處理過(guò)程是按照Touch事件從上到下傳遞州刽,再按照是否消費(fèi)的返回值,從下到上返回浪箭,即如果View的onTouchEvent返回false穗椅,將會(huì)向上傳給它的parent的ViewGroup,如果ViewGroup不處理奶栖,將會(huì)一直向上返回到Activity匹表。即隧道式向下分發(fā),然后冒泡式向上處理宣鄙。
二袍镀、3個(gè)重要的方法的講解
1、 Android 中與 Touch 事件相關(guān)的方法包括:dispatchTouchEvent(MotionEvent ev)冻晤、onInterceptTouchEvent(MotionEvent ev)苇羡、onTouchEvent(MotionEvent ev);能夠響應(yīng)這些方法的控件包括:ViewGroup明也、View宣虾、Activity。方法與控件的對(duì)應(yīng)關(guān)系如下表所示:
Touch 事件相關(guān)方法 | 方法功能 | View | ViewGroup | Activity |
---|---|---|---|---|
public boolean dispatchTouchEvent(MotionEvent ev) | 事件分發(fā) | Yes | Yes | Yes |
public boolean onInterceptTouchEvent(MotionEvent ev) | 事件攔截 | Yes | Yes / No | No |
public boolean onTouchEvent(MotionEvent ev) | 事件響應(yīng) | Yes | Yes | Yes |
2温数、小結(jié)
從這張表中我們可以看到 ViewGroup 和 View 對(duì)與 Touch 事件相關(guān)的三個(gè)方法均能響應(yīng)绣硝,而 Activity 對(duì)onInterceptTouchEvent(MotionEvent ev) 也就是事件攔截不進(jìn)行響應(yīng)。另外需要注意的是 View 對(duì) onInterceptTouchEvent(MotionEvent ev) 的響應(yīng)的前提是可以向該 View 中添加子 View撑刺,如果當(dāng)前的 View 已經(jīng)是一個(gè)最小的單元 View(比如 TextView)鹉胖,那么就無(wú)法向這個(gè)最小 View 中添加子 View,也就無(wú)法向子 View 進(jìn)行事件的攔截够傍,所以它沒有 onInterceptTouchEvent(MotionEvent ev)甫菠。
3、三個(gè)方法的用法:
1冕屯、)dispatchTouchEvent() 用來(lái)分派事件寂诱。
其中調(diào)用了onInterceptTouchEvent()和onTouchEvent(),一般不重寫該方法
2安聘、)onInterceptTouchEvent() 用來(lái)攔截事件痰洒。
ViewGroup類中的源碼實(shí)現(xiàn)就是{return false;}表示不攔截該事件,
事件將向下傳遞(傳遞給其子View)浴韭;
若手動(dòng)重寫該方法丘喻,使其返回true則表示攔截,事件將終止向下傳遞念颈,
事件由當(dāng)前ViewGroup類來(lái)處理泉粉,就是調(diào)用該類的onTouchEvent()方法
3、)onTouchEvent() 用來(lái)處理事件。
返回true則表示該View能處理該事件嗡靡,事件將終止向上傳遞(傳遞給其父View)跺撼;返回false表示不能處理,則把事件傳遞給其父View的onTouchEvent()方法來(lái)處理
【注】:ViewGroup的某些子類(GridView叽躯、ScrollView...)重寫了onInterceptTouchEvent()方法财边,當(dāng)發(fā)生ACTION_MOVE事件時(shí),返回true進(jìn)行攔截点骑。
四、Touch 事件分析
(一)谍夭、事件分發(fā):public boolean dispatchTouchEvent(MotionEvent ev)
Touch 事件發(fā)生時(shí) Activity 的 dispatchTouchEvent(MotionEvent ev) 方法會(huì)以隧道方式(從根元素依次往下傳遞直到最內(nèi)層子元素或在中間某一元素中由于某一條件停止傳遞)將事件傳遞給最外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法黑滴,并由該 View 的 dispatchTouchEvent(MotionEvent ev) 方法對(duì)事件進(jìn)行分發(fā)。
(二)紧索、事件攔截:public boolean onInterceptTouchEvent(MotionEvent ev)
在外層 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系統(tǒng)默認(rèn)的 super.dispatchTouchEvent(ev) 情況下袁辈,事件會(huì)自動(dòng)的分發(fā)給當(dāng)前 View 的 onInterceptTouchEvent 方法。onInterceptTouchEvent 的事件攔截邏輯如下:
?如果 onInterceptTouchEvent 返回 true珠漂,則表示將事件進(jìn)行攔截晚缩,并將攔截到的事件交由當(dāng)前 View 的 onTouchEvent 進(jìn)行處理;
?如果 onInterceptTouchEvent 返回 false媳危,則表示將事件放行荞彼,當(dāng)前 View 上的事件會(huì)被傳遞到子 View 上,再由子 View 的 dispatchTouchEvent 來(lái)開始這個(gè)事件的分發(fā)待笑;
?如果 onInterceptTouchEvent 返回 super.onInterceptTouchEvent(ev)鸣皂,事件默認(rèn)不會(huì)被攔截,并將攔截到的事件交由當(dāng)前 View 的 onTouchEvent 進(jìn)行處理暮蹂。
(三)寞缝、事件響應(yīng):public boolean onTouchEvent(MotionEvent ev)
在 dispatchTouchEvent 返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent 返回 true 或返回 super.onInterceptTouchEvent(ev) 的情況下 onTouchEvent 會(huì)被調(diào)用。onTouchEvent 的事件響應(yīng)邏輯如下:
?如果事件傳遞到當(dāng)前 View 的 onTouchEvent 方法仰泻,而該方法返回了 false荆陆,那么這個(gè)事件會(huì)從當(dāng)前 View 向上傳遞,并且都是由上層 View 的 onTouchEvent 來(lái)接收集侯,如果傳遞到上面的 onTouchEvent 也返回 false被啼,這個(gè)事件就會(huì)“消失”,而且接收不到下一次事件浅悉。
?如果返回了 true 則會(huì)接收并消費(fèi)該事件趟据。
?如果返回 super.onTouchEvent(ev) 默認(rèn)處理事件的邏輯和返回 false 時(shí)相同。
onInterceptTouchEvent用于改變事件的傳遞方向术健。決定傳遞方向的是返回值汹碱,返回為false時(shí)事件會(huì)傳遞給子控件,返回值為true時(shí)事件會(huì)傳遞給當(dāng)前控件的onTouchEvent()荞估,這就是所謂的Intercept(攔截)咳促。ii
正確的使用方法是稚新,在此方法內(nèi)僅判斷事件是否需要攔截,然后返回跪腹。即便需要攔截也應(yīng)該直接返回true褂删,然后由onTouchEvent方法進(jìn)行處理。
onTouchEvent用于處理事件冲茸,返回值決定當(dāng)前控件是否消費(fèi)(consume)了這個(gè)事件屯阀。尤其對(duì)于ACTION_DOWN事件,返回true轴术,表示我想要處理后續(xù)事件难衰;返回false,表示不關(guān)心此事件逗栽,并返回由父類進(jìn)行處理盖袭。
可能你要問(wèn)是否消費(fèi)了又區(qū)別嗎,反正我已經(jīng)針對(duì)事件編寫了處理代碼彼宠?答案是有區(qū)別鳄虱!比如ACTION_MOVE或者ACTION_UP發(fā)生的前提是一定曾經(jīng)發(fā)生了ACTION_DOWN,如果你沒有消費(fèi)ACTION_DOWN凭峡,那么系統(tǒng)會(huì)認(rèn)為ACTION_DOWN沒有發(fā)生過(guò)拙已,所以ACTION_MOVE或者ACTION_UP就不能被捕獲。
在沒有重寫onInterceptTouchEvent()和onTouchEvent()的情況下(他們的返回值都是false)
Android系統(tǒng)中的每個(gè)View的子類都具有下面三個(gè)和TouchEvent處理密切相關(guān)的方法:
1)public boolean dispatchTouchEvent(MotionEvent ev) 這個(gè)方法用來(lái)分發(fā)TouchEvent
2)public boolean onInterceptTouchEvent(MotionEvent ev) 這個(gè)方法用來(lái)攔截TouchEvent
3)public boolean onTouchEvent(MotionEvent ev) 這個(gè)方法用來(lái)處理TouchEvent
1想罕、如果dispatchTouchEvent返回true 悠栓,則交給這個(gè)view的onTouchEvent處理, 如果最終需要處理事件的view的onTouchEvent()返回了false按价,那么該事件將被傳遞至其上一層次的view的onTouchEvent()處理惭适。如果最終需要處理事件的view 的onTouchEvent()返回了true,那么后續(xù)事件將可以繼續(xù)傳遞給該view的onTouchEvent()處理楼镐。
2癞志、如果dispatchTouchEvent返回 false ,則交給這個(gè) view的interceptTouchEvent方法來(lái)決定是否
要攔截這個(gè)事件框产,如果 interceptTouchEvent 返回 true 凄杯,表示攔截掉了,則交給它的 onTouchEvent 來(lái)處理秉宿,如果 interceptTouchEvent 返回 false 戒突,那么就傳遞給子view ,由子 view 的 dispatchTouchEvent 再來(lái)開始這個(gè)事件的分發(fā)描睦。
3膊存、如果事件傳遞到某一層的子 view 的onTouchEvent 上了,這個(gè)方法返回了 false ,那么這個(gè)事件
會(huì)從這個(gè)view 往上傳遞隔崎,都是 onTouchEvent 來(lái)接收今艺。如果傳遞到最上面的 onTouchEvent 也返回 false 的話,這個(gè)事件就會(huì)“消失”爵卒,而且接收不到下一次事件虚缎。