Android View的事件分發(fā)機(jī)制

觸摸事件

在用戶觸摸屏幕時挟鸠,總是離用戶觸摸點最近的控件來響應(yīng)觸摸事件叉信,如果最近的控件沒有實現(xiàn)響應(yīng)事件,那這個事件會不斷的向父類傳遞艘希,直到有view響應(yīng)時硼身,就會將觸摸反饋的事件流傳遞給這個view的onTouchEvent()方法,如下圖: 如果CustmoView中不響應(yīng)onTouchEvent()覆享,那面事件會傳遞給LayoutView中佳遂,如果在LayoutView中響應(yīng)了onTouchEvent(),那面事件就不會再傳遞給RootView了撒顿。

Android 自定義觸摸反饋事件時丑罪,通常都是如下的寫法:

public class MyView {
    // ...

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                //...
                break;
            case MotionEvent.ACTION_MOVE:
                //...
                break;
            case MotionEvent.ACTION_UP:
                //...
                break;
        }
        return true;
    }
}

復(fù)寫onTouchEvent()然后在這里面處理觸摸反饋的事件流。
tips:
1.return true 代表本次事件流在這里消費凤壁,ACTION_DOWN 時候返回true 才是有效的吩屹。 這樣事件就不會再傳遞給父類進(jìn)行處理。
2.觸摸反饋事件流是以ACTION_DOWN開始拧抖,以ACTION_UP或者ACTION_CANCEL結(jié)束的一組事件煤搜,例如:
按鈕點擊事件的觸摸反饋事件流
ACTION_DOWN -> ACTION_MOVE -> ACTION_MOVE -> ACTION_UP
被中止事件的觸摸反饋事件流
ACTION_DOWN -> ACTION_MOVE -> ACTION_CANCEL

事件攔截

現(xiàn)在有如下這樣的一種場景:
一個Listview, Listview中的每一項itme中都有個ButtonButton中的實現(xiàn) 重寫了onTouchEvent()方法來自定義觸摸事件

場景1:
用戶點擊Button唧席,然后松開手指擦盾。
結(jié)果:
產(chǎn)生點擊事件,事件流是這樣的:
原因:
Button是離用戶觸摸點最近的控件淌哟,并且消費了本次的事件流迹卢。
ACTION_DOWN -> ACTION_MOVE -> ACTION_MOVE -> ACTION_UP

場景2:
用戶點擊Button,向上滑動绞绒。
結(jié)果:
不會觸發(fā)Button的點擊事件婶希,而是Listview開始滑動。
這次為什么不是Button消費了本次的事件流呢蓬衡?
原因:
關(guān)鍵在onInterceptEvent()這里喻杈。
分析:

@Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
         // dispatchTouchEvent 事件分發(fā)的時候會先檢查事件是否被攔截
         // Check for interception.
         final boolean intercepted;
           // ... 刪除了無關(guān)代碼
          // Update list of touch targets for pointer down, if needed.
            final boolean split = (mGroupFlags & FLAG_SPLIT_MOTION_EVENTS) != 0;
            TouchTarget newTouchTarget = null;
            boolean alreadyDispatchedToNewTouchTarget = false;
            if (!canceled && !intercepted) {
                
                         // ... 刪除了無關(guān)代碼
                                // 沒有被攔截,才會執(zhí)行之后的onTouch事件狰晚,dispatchTransformedTouchEvent 中會分發(fā)onTouchEvent事件
                      if (dispatchTransformedTouchEvent(ev, cancelChild,
                                target.child, target.pointerIdBits)) {
                            handled = true;
                        }
             }
}

MotionEvent事件是從根視圖開始分發(fā)的筒饰,上面的dispatchTouchEvent() 負(fù)責(zé)事件分發(fā)。 每次MotionEvent事件都會先詢問上級視圖是否需要攔截本次事件流壁晒,一但上級視圖返回了true瓷们,那么后續(xù)的事件流就都會直接傳遞給這個視圖的onTouchEvent()方法,不會再傳遞給之后的視圖了。
這也就解釋了為什么點擊Button谬晕,向上滑動不是觸發(fā)點擊事件而是觸發(fā)了Listview的滑動事件碘裕。這是因為ListviewonInterceptEvent()中判斷出本次是滑動事件,從而攔截了本次事件流攒钳,來讓自己處理本次事件流帮孔。

tips:
1. onTouchEvent() 函數(shù)中只有ACTION_DOWN時返回true才是有效的,若ACTION_DOWN沒有返回true不撑,那么后續(xù)的事件流也就不會再進(jìn)來了文兢,和這個view也就無緣了。
1. onInterceptEvent() 函數(shù)中可以在最開始ACTION_DOWN時返回false焕檬,然后再之后的事件流中來判斷是否需要開始攔截本次事件流姆坚,也就是說可以在之后事件流的過程中來判斷是否達(dá)到觸發(fā)攔截條件,從而來開始攔截

阻止上級事件攔截

現(xiàn)在有如下這樣的一種場景:
在一個類似Listview的支持滾動的自定義View中, View中有個Button实愚,Button中的實現(xiàn) 重寫了onTouchEvent()方法來自定義觸摸事件兼呵,長按后支持Button上下移動。

場景3:
用戶點擊Button爆侣,長按后向上滑動萍程。
結(jié)果:
不會觸發(fā)View滑動,而是Button在移動
這次為什么View中的onInterceptEvent()沒有攔截到移動的事件流呢兔仰?
原因:
關(guān)鍵在requestDisallowInterceptTouchEvent()這里
分析:
requestDisallowInterceptTouchEvent()是告訴上級視圖,不要攔截本次的事件流蕉鸳。
這個設(shè)置是臨時的乎赴,也就是只對本次事件流有效。 下次事件流發(fā)生時候潮尝,如果需要還必須要重新調(diào)用一次榕吼。

End!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末勉失,一起剝皮案震驚了整個濱河市羹蚣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乱凿,老刑警劉巖顽素,帶你破解...
    沈念sama閱讀 222,729評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異徒蟆,居然都是意外死亡胁出,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評論 3 399
  • 文/潘曉璐 我一進(jìn)店門段审,熙熙樓的掌柜王于貴愁眉苦臉地迎上來全蝶,“玉大人,你說我怎么就攤上這事∫忠” “怎么了绷落?”我有些...
    開封第一講書人閱讀 169,461評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長始苇。 經(jīng)常有香客問我砌烁,道長,這世上最難降的妖魔是什么埂蕊? 我笑而不...
    開封第一講書人閱讀 60,135評論 1 300
  • 正文 為了忘掉前任往弓,我火速辦了婚禮,結(jié)果婚禮上蓄氧,老公的妹妹穿的比我還像新娘函似。我一直安慰自己,他們只是感情好喉童,可當(dāng)我...
    茶點故事閱讀 69,130評論 6 398
  • 文/花漫 我一把揭開白布撇寞。 她就那樣靜靜地躺著,像睡著了一般堂氯。 火紅的嫁衣襯著肌膚如雪南誊。 梳的紋絲不亂的頭發(fā)上笋庄,一...
    開封第一講書人閱讀 52,736評論 1 312
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼嗓化。 笑死,一個胖子當(dāng)著我的面吹牛蜕径,可吹牛的內(nèi)容都是我干的栈拖。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼授段,長吁一口氣:“原來是場噩夢啊……” “哼蹲蒲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侵贵,我...
    開封第一講書人閱讀 40,124評論 0 277
  • 序言:老撾萬榮一對情侶失蹤届搁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后窍育,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卡睦,經(jīng)...
    沈念sama閱讀 46,657評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,723評論 3 342
  • 正文 我和宋清朗相戀三年蔫骂,在試婚紗的時候發(fā)現(xiàn)自己被綠了么翰。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,872評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡辽旋,死狀恐怖浩嫌,靈堂內(nèi)的尸體忽然破棺而出檐迟,到底是詐尸還是另有隱情,我是刑警寧澤码耐,帶...
    沈念sama閱讀 36,533評論 5 351
  • 正文 年R本政府宣布追迟,位于F島的核電站,受9級特大地震影響骚腥,放射性物質(zhì)發(fā)生泄漏敦间。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,213評論 3 336
  • 文/蒙蒙 一束铭、第九天 我趴在偏房一處隱蔽的房頂上張望廓块。 院中可真熱鬧,春花似錦契沫、人聲如沸带猴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,700評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拴清。三九已至,卻和暖如春会通,著一層夾襖步出監(jiān)牢的瞬間口予,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,819評論 1 274
  • 我被黑心中介騙來泰國打工涕侈, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留沪停,地道東北人。 一個月前我還...
    沈念sama閱讀 49,304評論 3 379
  • 正文 我出身青樓裳涛,卻偏偏與公主長得像牙甫,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子调违,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,876評論 2 361

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