觸摸反饋事件分發(fā)優(yōu)化吸收

views.png

產(chǎn)生疑問:對于一個按鈕,我按下抬起時草戈,觸發(fā)了該按鈕的 onClick() 方法,可是我按下然后滑動時侍瑟,我卻可以使該按鈕的父View開始滑動唐片。這個情景一定不陌生丙猬,我們的ListViewGridView經(jīng)常有這種操作出現(xiàn)。那么我們的系統(tǒng)是如何做到的呢费韭?靠的就是觸摸事件分發(fā)機制


觸摸事件單元:

按下 (ACTION_DOWN).

移動 (ACTION_MOVE).

抬起 (ACTION_UP).

取消 *(ATCION_CANCEL).

按下 (ACTION_DOWN) 開始茧球,(中間可能包含某些移動 (ACTION_MOVE) 事件)抬起 (ACTION_UP)取消 (ACTION_CANCEL) 結束的一系列觸摸事件的集合被稱為觸摸事件流


例如 onClick() 事件:

按下(ACTION_DOWN), 加上 抬起 (ACTION_UP),這組事件流就構成了 onClick() 事件星持。


觸摸事件會傳入View的onTouchEvent() 方法中:

public class mView extends View{
    ...
    @Override
    public boolean onTouchEvent(MotionEvent event){
        switch(event.getActionMasked()){
            case MotionEvent.ACTION_UP:
            // Do something
            ...
        }
        
        return true;
    }
}

/*
event參數(shù)中包含了各種觸摸操作的信息:包括事件類型(是按下抢埋,抬起還是其他),坐標督暂,等等揪垄。
*/

函數(shù)返回類型為boolean,我們知道所有觸摸事件流都只能是從 按下 (ACTION_DOWN) 開始的
逻翁,這個方法從用戶觸摸的點開始由上而下依次向各級View詢問:你是否要消費這組事件饥努?哪個View的onTouchEvent() 方法先接受到 按下(ACTION_DOWN) 事件,并返回了true八回,哪個View就接管了這個事件流酷愧,后續(xù)的觸摸事件都將交給這個View執(zhí)行。

根據(jù)置頂圖舉個例子:用戶點擊了子View缠诅,那么系統(tǒng)開始從子View開始由上而下依次調用子View溶浴,父View,爺View的onTouchEvent()
方法滴铅,哪個View的該方法在接收到按下(ACTION_DOWN) 事件后返回了true戳葵,哪個View就開始處理這個按下(ACTION_DOWN) 事件的后續(xù)所有事件就乓,直到抬起(ACTION_UP) 事件或者取消(ACTION_CANCEL) 事件傳入汉匙。在這三個View中,如果沒有重寫它們的onTouchEvent() 方法生蚁,那么子View的onTouchEvent() 在率先接收到按下(ACTION_DOWN) 事件后會接管后續(xù)事件直到事件結束噩翠。如果子View在接收到按下(ACTION_DOWN) 事件時返回了false,那么系統(tǒng)會繼續(xù)向下去詢問父View邦投,你要不要接管這組事件伤锚。以此類推。

袁隆平.png


不瞞你說志衣,其實在進行從上往下調用onTouchEvent() 之前屯援,系統(tǒng)偷偷地從最底下的那個根View 依次向上逐級調用了onInterceptTouchEvent() 方法。產(chǎn)生任何觸摸事件時都會由下而上地調用各級View的onInterceptTouchEvent() 來詢問是否攔截事件念脯。該方法默認返回false狞洋,也就是不攔截,由于onInterceptTouchEvent() 會監(jiān)聽任何觸摸事件绿店,所以你可以在該方法內寫入自己的算法吉懊,并返回true庐橙,以達成某個View在滿足特定條件后立即接管該事件流后續(xù)事件的目的。在接管了該事件流后借嗽,新的接管者將把后續(xù)觸摸事件傳入自己的onTouchEvent()方法中處理态鳖,并且新的接管者將向前任接管者發(fā)送取消(ACTION_CANCEL) 事件(我接盤了!)來徹底停止前任接管者的處理中間狀態(tài)恶导。這個就叫做事件攔截機制浆竭。

public class mViewGroup extends ViewGroup{
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event){
        switch(event.getActionMasked()){
            ...
            if(符合條件){
                return true;
            }
        }
        return false;
    }
    
    @Override
    public boolean onTouchEvent(MotionEvent event){
        switch(event.getActionMasked()){
            ...
        }
        
        return true;
    }
}

綜合之前的onTouchEvent() 方法,我們梳理一下這兩個方法之間的順序:當某一觸摸事件傳入系統(tǒng)時惨寿,系統(tǒng)先由下而上地執(zhí)行各級View的onInterceptTouchEvent() 方法兆蕉。再由上而下地執(zhí)行各級View的onTouchEvent() 方法。

views.png
根據(jù)這個圖片再舉個例子:我在父View的onInterceptTouchEvent() 方法里寫了自己的算法缤沦,寫的是當用戶開始滑動時虎韵,父View的onInterceptTouchEvent() 返回true,攔截機制啟用缸废。那么未滑動時包蓝,比如點擊事件觸發(fā)時,父View不會攔截子View的任何觸摸事件企量,子View可以自由地實現(xiàn)onClick() 方法测萎。一旦用戶在執(zhí)行按下(ACTION_DOWN) 后開始滑動,父View將立刻接管這個事件流届巩,并將后續(xù)觸摸事件傳入自己的onTouchEvent() 中處理硅瞧。你完全可以將ListView 中的item看做圖中的子View,將ListView 自身看做圖中的父View恕汇。


沒錯腕唧,我又要不瞞你說了。還想說一個方法:requestDisallowInterceptTouchEvent()瘾英。這個方法是在子View 中調用的枣接,用來阻止其父ViewonInterceptTouchEvent() 方法生效。并且它會遞歸地阻止每一級父View 的攔截方法缺谴。例如我想在滑動屏幕時移動父View 但惶,長按我的子View后的滑動可以移動子View 本身而不是父View,那么我在子ViewonTouchEvent() 方法里適當?shù)牡胤綄懮?strong>requestDisallowInterceptTouchEvent() 就能實現(xiàn)特殊的需求湿蛔。

例如我可以在子View 的長按的case 下調用該方法膀曾,那么接下來的移動(ATCION_MOVE) 事件就不會交給父ViewonTouchEvent() 執(zhí)行了。


最后不瞞你說阳啥,感謝Hencoder項目添谊,感謝朱凱老師,本文是朱老師課后的學習心得總結苫纤。

zhukai.png

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末碉钠,一起剝皮案震驚了整個濱河市纲缓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌喊废,老刑警劉巖祝高,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異污筷,居然都是意外死亡工闺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門瓣蛀,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陆蟆,“玉大人,你說我怎么就攤上這事惋增〉螅” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵诈皿,是天一觀的道長林束。 經(jīng)常有香客問我,道長稽亏,這世上最難降的妖魔是什么壶冒? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮截歉,結果婚禮上胖腾,老公的妹妹穿的比我還像新娘。我一直安慰自己瘪松,他們只是感情好咸作,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著凉逛,像睡著了一般性宏。 火紅的嫁衣襯著肌膚如雪群井。 梳的紋絲不亂的頭發(fā)上状飞,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天,我揣著相機與錄音书斜,去河邊找鬼诬辈。 笑死,一個胖子當著我的面吹牛荐吉,可吹牛的內容都是我干的焙糟。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼样屠,長吁一口氣:“原來是場噩夢啊……” “哼穿撮!你這毒婦竟也來了缺脉?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤悦穿,失蹤者是張志新(化名)和其女友劉穎攻礼,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栗柒,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡礁扮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瞬沦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片太伊。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖逛钻,靈堂內的尸體忽然破棺而出僚焦,到底是詐尸還是另有隱情,我是刑警寧澤曙痘,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布叠赐,位于F島的核電站,受9級特大地震影響屡江,放射性物質發(fā)生泄漏芭概。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一惩嘉、第九天 我趴在偏房一處隱蔽的房頂上張望罢洲。 院中可真熱鬧,春花似錦文黎、人聲如沸惹苗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桩蓉。三九已至,卻和暖如春劳闹,著一層夾襖步出監(jiān)牢的瞬間院究,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工本涕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留业汰,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓菩颖,卻偏偏與公主長得像样漆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子晦闰,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361