Android觸摸滑動(dòng)全解(二)——ViewGroup中觸摸事件詳解

Android觸摸滑動(dòng)全解(二)——ViewGroup中觸摸事件詳解

VieGroup觸摸事件概述

ViewGroup繼承自View介牙,很多方法都和View中一樣,不同的是它重載了dispatchTouchEvent()方法,并且它多了一個(gè)自身的方法onInterceptTouchEvent()削饵。

ViewGroup觸摸事件調(diào)用原則

  • dispatchTouchEvent()中,會(huì)對(duì)子View進(jìn)行遞歸,將dispatchTouchEvent()傳遞給它的每一個(gè)子View锣枝,如果某一個(gè)子View在ACTION_DOWN的時(shí)候沒(méi)有消費(fèi)或者攔截事件,那么這個(gè)子View后續(xù)也將無(wú)法收到ACTIION_MOVEACTION_UP等事件兰英。

  • ViewGroup可以在onInterceptTouchEvent()中攔截事件撇叁,onInterceptTouchEvent()在之后執(zhí)行,如果返回true畦贸,則會(huì)執(zhí)行自身的onTouchEvent()方法陨闹,但后續(xù)onInterceptTouchEvent()onTouchEvent()將不會(huì)調(diào)用楞捂。

  • ViewGroup如果onInterceptTouchEvent()返回false,那么ViewGroup后續(xù)是否繼續(xù)調(diào)用dispatchTouchEvent()取決于子View是否消費(fèi)觸摸事件趋厉。

  • ViewGroup如果返回在dispatchTouchEvent()中返回false寨闹,那么后續(xù)所有的觸摸操作都不會(huì)再執(zhí)行!

  • ViewGroup在dispatchTouchEvent()return truereturn super.dispatchTouchEvent(ev)會(huì)導(dǎo)致觸摸結(jié)果不一樣君账!

ViewGroup攔截觸摸事件示例

自定義一個(gè)ViewGroup繼承LinearLayout繁堡,展示ViewGroup對(duì)觸摸事件的攔截。子View默認(rèn)消費(fèi)此事件乡数。

1椭蹄、正常狀態(tài)(子View消費(fèi)觸摸事件)

此時(shí):
ViewGroup:dispatchTouchEvent()super.dispatchTouchEvent(ev)onInterceptTouchEvent()false净赴,OnTouchEvent()false绳矩。
子View:dispatchTouchEvent()返回trueOnTouchEvent()返回true劫侧。

Log打勇癯辍:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    View dispatchTouchEvent down
    View onTouchEvent down

zw: LinearLayout dispatchTouchEvent move
    LinearLayout onInterceptTouchEvent move
    View dispatchTouchEvent move
    View onTouchEvent move

zw: LinearLayout dispatchTouchEvent up
    LinearLayout onInterceptTouchEvent up
    View dispatchTouchEvent up
    View onTouchEvent up

可以看見(jiàn),子View將事件消費(fèi)掉了烧栋,因此ViewGroup沒(méi)有調(diào)用OnTouchEvent()方法写妥。

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > View.dispatchTouchEvent(DOWN) > View.OnTouchEvent(DOWN) >
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE) > ViewGroup.onInterceptTouchEvent(MOVE) > View.dispatchTouchEvent(MOVE) > View.OnTouchEvent(MOVE) >
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP) > ViewGroup.onInterceptTouchEvent(UP) > View.dispatchTouchEvent(UP) > View.OnTouchEvent(UP) > 結(jié)束

2、正常狀態(tài)(子View不消費(fèi)觸摸事件)

此時(shí):
ViewGroup:dispatchTouchEvent()super.dispatchTouchEvent(ev)审姓,onInterceptTouchEvent()false珍特,OnTouchEvent()false
子View:dispatchTouchEvent()返回false魔吐,OnTouchEvent()返回false扎筒。

Log打印:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    View dispatchTouchEvent down
    View onTouchEvent down
    LinearLayout onTouchEvent down

可以看見(jiàn)酬姆,子View沒(méi)有將事件消費(fèi)掉嗜桌,因此ViewGroup調(diào)用OnTouchEvent()方法。

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > View.dispatchTouchEvent(DOWN) > View.OnTouchEvent(DOWN) > ViewGroup.onTouchEvent(DOWN) > 結(jié)束

3辞色、ViewGroup攔截但不消費(fèi)觸摸事件(子View消費(fèi)觸摸事件)

此時(shí):
ViewGroup:dispatchTouchEvent()super.dispatchTouchEvent(ev)骨宠,onInterceptTouchEvent()trueOnTouchEvent()false相满。
子View:dispatchTouchEvent()返回true层亿,OnTouchEvent()返回true

Log打恿⒚馈:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    LinearLayout onTouchEvent down

可以看見(jiàn)匿又,子View沒(méi)有將事件消費(fèi)掉,因?yàn)閂iewGroup的onInterceptTouchEvent()返回了true建蹄,攔截了此次事件碌更,但是它本身也沒(méi)有消費(fèi)裕偿,因此,ACTION_DOWN后面沒(méi)有再繼續(xù)執(zhí)行了针贬。

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > ViewGroup.onTouchEvent(DOWN) > 結(jié)束

4击费、ViewGroup攔截并消費(fèi)觸摸事件(子View消費(fèi)觸摸事件)

此時(shí):
ViewGroup:dispatchTouchEvent()super.dispatchTouchEvent(ev)onInterceptTouchEvent()true桦他,OnTouchEvent()true
子View:dispatchTouchEvent()返回true谆棱,OnTouchEvent()返回true快压。

Log打印:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    LinearLayout onTouchEvent down

zw: LinearLayout dispatchTouchEvent move
    LinearLayout onTouchEvent move

zw: LinearLayout dispatchTouchEvent up
    LinearLayout onTouchEvent up

可以看見(jiàn)垃瞧,子View沒(méi)有將事件消費(fèi)掉蔫劣,因?yàn)閂iewGroup的onInterceptTouchEvent()返回了true,攔截了此次事件个从,但是它本身消費(fèi)了此次事件脉幢,因此,只有ViewGroup自身在消費(fèi)本次觸摸事件嗦锐。

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > ViewGroup.onTouchEvent(DOWN) >
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE) > ViewGroup.onTouchEvent(MOVE) >
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP) > ViewGroup.onTouchEvent(UP) >

5嫌松、ViewGroup沒(méi)攔截但消費(fèi)觸摸事件(子View消費(fèi)觸摸事件)

此時(shí):
ViewGroup:dispatchTouchEvent()super.dispatchTouchEvent(ev)onInterceptTouchEvent()false奕污,OnTouchEvent()true萎羔。
子View:dispatchTouchEvent()返回trueOnTouchEvent()返回true碳默。

Log打蛹窒荨:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    View dispatchTouchEvent down
    View onTouchEvent down

zw: LinearLayout dispatchTouchEvent move
    LinearLayout onInterceptTouchEvent move
    View dispatchTouchEvent move
    View onTouchEvent move

zw: LinearLayout dispatchTouchEvent up
    LinearLayout onInterceptTouchEvent up
    View dispatchTouchEvent up
    View onTouchEvent up

可以看見(jiàn),如果ViewGroup的onInterceptTouchEvent()沒(méi)有返回truedispatchTouchEvent()返回true嘱根,那么即使OnTouchEvent()返回的是true髓废,也不會(huì)調(diào)用OnTouchEvent()方法,需要根據(jù)子View的消費(fèi)情況來(lái)判斷该抒!

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > View.dispatchTouchEvent(DOWN) > View.onTouchEvent(DOWN) >
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE) > ViewGroup.onInterceptTouchEvent(MOVE) > View.dispatchTouchEvent(MOVE) > View.onTouchEvent(MOVE) >
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP) >ViewGroup.onInterceptTouchEvent(UP) > View.dispatchTouchEvent(UP) > View.onTouchEvent(UP) >

子View強(qiáng)制消費(fèi)觸摸事件的方法

當(dāng)ViewGroup在onInterceptTouchEvent()返回true消費(fèi)事件后慌洪,子View則無(wú)法消費(fèi)此觸摸事件,此時(shí)柔逼,子View如果一定要消費(fèi)此觸摸事件的話蒋譬,可以使用getParent().requestDisallowInterceptTouchEvent(true)來(lái)讓ViewGroup不攔截本次事件。
但是此方法需要滿足一個(gè)條件愉适,就是ViewGroup在onInterceptTouchEvent()的ACTION_DOWN時(shí)不要攔截犯助,如果攔截了,那么此方法失效维咸。

正常情況

此時(shí):
ViewGroup:dispatchTouchEvent()true剂买,onInterceptTouchEvent()在ACITON_DOWN時(shí)為false惠爽,其余返回trueOnTouchEvent()true瞬哼。
子View:dispatchTouchEvent()返回true婚肆,OnTouchEvent()返回true

Log打幼俊:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    View dispatchTouchEvent down
    View onTouchEvent down

zw: LinearLayout dispatchTouchEvent move
    LinearLayout onInterceptTouchEvent move
    LinearLayout dispatchTouchEvent move
    LinearLayout onTouchEvent move

zw: LinearLayout dispatchTouchEvent up
    LinearLayout onTouchEvent up

可以看見(jiàn)较性,子View只有dispatchTouchEvent(DOWN)onTouchEvent(DOWN)被調(diào)用了,其余的都被攔截了结胀。(這就是ViewGroup的onInterceptTouchEvent()必須在ACTION_DOWN時(shí)返回false的原因赞咙,不然子View根本沒(méi)有調(diào)用的機(jī)會(huì))

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > View.dispatchTouchEvent(DOWN) > View.onTouchEvent(DOWN)
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE) > ViewGroup.onInterceptTouchEvent(MOVE) > ViewGroup.dispatchTouchEvent(MOVE) > ViewGroup.onTouchEvent(MOVE)
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP) > ViewGroup.onTouchEvent(UP) > 結(jié)束

子View調(diào)用代碼的情況

基本和上面一樣,只是子View在onTouchEvent()的ACTION_DOWN中調(diào)用代碼:

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()){
        case MotionEvent.ACTION_DOWN:
            getParent().requestDisallowInterceptTouchEvent(true);
            Log.e("zw","onTouchEvent down");
            break;
        case MotionEvent.ACTION_MOVE:
            Log.e("zw","onTouchEvent move");
            break;
        case MotionEvent.ACTION_UP:
            Log.e("zw","onTouchEvent up");
            break;
    }
    return true;
}

Log打釉愀邸:

zw: LinearLayout dispatchTouchEvent down
    LinearLayout onInterceptTouchEvent down
    View dispatchTouchEvent down
    View onTouchEvent down

zw: LinearLayout dispatchTouchEvent move
    View dispatchTouchEvent move
    View onTouchEvent move

zw: LinearLayout dispatchTouchEvent up
    View dispatchTouchEvent up
    View onTouchEvent up

可以看見(jiàn)攀操,本次觸摸事件被子View強(qiáng)制消費(fèi)掉了。

調(diào)用順序:
ACTION_DOWN:
ViewGroup.dispatchTouchEvent(DOWN) > ViewGroup.onInterceptTouchEvent(DOWN) > View.dispatchTouchEvent(DOWN) > View.onTouchEvent(DOWN)
ACTION_MOVE:
ViewGroup.dispatchTouchEvent(MOVE) > View.dispatchTouchEvent(MOVE) > View.onTouchEvent(MOVE)
ACTION_UP:
ViewGroup.dispatchTouchEvent(UP) > View.dispatchTouchEvent(UP) >View.onTouchEvent(UP) > 結(jié)束

總結(jié)

1秸抚、如果ViewGroup要消費(fèi)觸摸事件的話速和,一定要在onInterceptTouchEvent()返回true,否則它是否調(diào)用onTouchEvent()方法取決于子View是否消費(fèi)此事件剥汤!
2颠放、ViewGroup的dispatchTouchEvent()中盡量不要直接返回truefalse,因?yàn)檫@樣導(dǎo)致ViewGroup不會(huì)再去分發(fā)任何事件秀姐!最好返回super.dispatchTouchEvent(ev)慈迈!
3、子View可以通過(guò)調(diào)用getParent().requestDisallowInterceptTouchEvent(true)方法來(lái)強(qiáng)制消費(fèi)事件(有限制條件)省有。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末痒留,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蠢沿,更是在濱河造成了極大的恐慌伸头,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舷蟀,死亡現(xiàn)場(chǎng)離奇詭異恤磷,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)野宜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)扫步,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人匈子,你說(shuō)我怎么就攤上這事河胎。” “怎么了虎敦?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵游岳,是天一觀的道長(zhǎng)政敢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)胚迫,這世上最難降的妖魔是什么喷户? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮访锻,結(jié)果婚禮上褪尝,老公的妹妹穿的比我還像新娘。我一直安慰自己期犬,他們只是感情好恼五,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著哭懈,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茎用。 梳的紋絲不亂的頭發(fā)上遣总,一...
    開(kāi)封第一講書(shū)人閱讀 49,764評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音轨功,去河邊找鬼旭斥。 笑死,一個(gè)胖子當(dāng)著我的面吹牛古涧,可吹牛的內(nèi)容都是我干的垂券。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼羡滑,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼菇爪!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起柒昏,我...
    開(kāi)封第一講書(shū)人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤凳宙,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后职祷,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體氏涩,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年有梆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了是尖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡泥耀,死狀恐怖饺汹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情爆袍,我是刑警寧澤首繁,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布作郭,位于F島的核電站,受9級(jí)特大地震影響弦疮,放射性物質(zhì)發(fā)生泄漏夹攒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一胁塞、第九天 我趴在偏房一處隱蔽的房頂上張望咏尝。 院中可真熱鬧,春花似錦啸罢、人聲如沸编检。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)允懂。三九已至,卻和暖如春衩匣,著一層夾襖步出監(jiān)牢的瞬間蕾总,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工琅捏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留生百,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓柄延,卻偏偏與公主長(zhǎng)得像蚀浆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子搜吧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容