iOS事件分發(fā)機(jī)制介紹與應(yīng)用

iOS事件分發(fā)機(jī)制介紹與應(yīng)用

打開某App點(diǎn)擊登錄按鈕后彈出登錄頁面娇妓。這是一個(gè)事件分發(fā)與響應(yīng)的示例。我們來探究下該過程逗鸣。

介紹事件分發(fā)機(jī)制自然繞不開事件乍构。

iOS包含以下幾種類型事件:

  • 觸摸事件
  • 按壓時(shí)間
  • 搖動事件
  • 遠(yuǎn)程控制事件
  • 編輯菜單時(shí)間

本文選擇以觸摸事件進(jìn)行介紹。因?yàn)橄鄬Χ运氖录职l(fā)機(jī)制最全面柳譬。

iOS事件分發(fā)流程

iOS應(yīng)用啟動后UIApplicationMain函數(shù)會創(chuàng)建一個(gè)UIApplication的單例喳张。該單例會維護(hù)一個(gè)FIFO的隊(duì)列進(jìn)行事件分發(fā)。系統(tǒng)檢測到觸摸事件后就會發(fā)給當(dāng)前Application單例美澳,由該單例進(jìn)行派發(fā)销部。派發(fā)分為下面三個(gè)過程:

一摸航、hitTest

UIWindow一旦接收到事件后就進(jìn)行hit-test以查找哪個(gè)對象接收該事件。hitTest:withEvent方法用于發(fā)現(xiàn)在觸摸位置的視圖舅桩。pointInside:withEvent:用于檢測該點(diǎn)擊是否在視圖的邊界內(nèi)酱虎。hitTest:withEvent調(diào)用pointInside:withEvent:

hitTest以遞歸的形式調(diào)用直至找到能處理觸摸事件的最頂部葉子視圖(一般就是手指點(diǎn)中區(qū)域所屬的視圖)擂涛,那么該視圖就會被選中读串。稱為第一響應(yīng)者。

做個(gè)類比就是:老板說我這有個(gè)事誰干給干了撒妈?經(jīng)過經(jīng)理等層層指派恢暖,大家都覺得小王合適。

該過程可以通過復(fù)寫下面方法斷點(diǎn)了解狰右。

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

具體情況如圖所示:

hit_test.png

二杰捂、sendEvent

一旦確定第一響應(yīng)者后,UIApplication單例就會發(fā)送相關(guān)觸摸事件到第一響應(yīng)者棋蚌。

就好比老本拍板說那就讓小王干了嫁佳。

該過程可以斷點(diǎn)button的處理方法進(jìn)行了解。如圖所示:


sent_enent

三附鸽、事件處理

針對觸摸事件的處理是重載如下方法:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

第一響應(yīng)者接到事件后有以下三種選擇:

  1. 什么都不不處理(選擇不重載上述方法)
  2. 處理一部分脱拼,剩下的交由其它對象處理(重載處理后調(diào)用super)
  3. 獨(dú)自進(jìn)行處理(重載處理并且不調(diào)用super)

如果第一響應(yīng)者什么都不處理或者處理部分然后調(diào)用super,則事件將被發(fā)送到一個(gè)鏈?zhǔn)巾憫?yīng)路徑中坷备,即響應(yīng)鏈。該事件遵循以下路徑進(jìn)行轉(zhuǎn)發(fā):

  1. 第一響應(yīng)者
  2. 第一響應(yīng)者的父視圖
  3. 父視圖的父視圖情臭,直至關(guān)聯(lián)的視圖控制器
  4. 視圖控制器的父視圖控制器省撑,直至根視圖
  5. 根視圖下一響應(yīng)者是window
  6. window的下一響應(yīng)者是application
  7. 最后的響應(yīng)者是App delegate

若轉(zhuǎn)發(fā)至App delegate,且App delegate未進(jìn)行處理則該事件將被丟棄俯在。

iOS處理方式

那么事件處理的方式有哪些?我們大致可以劃分為下面三類竟秫。

  1. UIControl的子類
  2. TouchEvent
  3. 觸摸相關(guān)手勢。

有可能一個(gè)對象同時(shí)實(shí)現(xiàn)了兩個(gè)或者更多處理方式跷乐。那么誰的優(yōu)先級高些呢肥败?

這個(gè)我們可以做個(gè)類比,讓你實(shí)現(xiàn)判斷鼠標(biāo)單機(jī)還是雙擊愕提,那么檢測單擊的時(shí)間會比雙擊要長馒稍。因?yàn)殡p擊失效后才會進(jìn)行單擊判定。
同理手勢識別不了了浅侨,其它才有機(jī)會處理纽谒,UIControl子類也類似,那么優(yōu)先級如下所示:

觸摸相關(guān)手勢 > UIControl的子類 > TouchEvent

一般情況下如输,我們遇到的是手勢觸發(fā)了就不會繼續(xù)轉(zhuǎn)發(fā)事件了鼓黔。
這就是為什么有人在UIButton中添加個(gè)tap手勢看起來正常(別笑)央勒。

事件分發(fā)機(jī)制應(yīng)用

事件分發(fā)不同場景方法選擇

  1. 更改事件分發(fā)流程,實(shí)現(xiàn)相關(guān)類的hitTest:withEvent:方法為佳澳化。

  2. 擴(kuò)大點(diǎn)擊范圍崔步,覆寫pointInside:withEvent:是個(gè)不錯(cuò)的選擇。

  3. 解決一寫如收起鍵盤等問題缎谷,可嘗試直接發(fā)送事件井濒。如:

    [[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil];
    
  4. 選擇讓父視圖或者關(guān)聯(lián)視圖控制器處理事件可以這么寫(雖然很少見有這么玩的):

    [button addTarget:nil action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
    

具體應(yīng)用場景

實(shí)現(xiàn)自定義懸浮窗

根據(jù)響應(yīng)鏈規(guī)則,我們能更好的設(shè)計(jì)一個(gè)自定義懸浮窗慎陵。

  1. 懸浮窗作為UIWindow的rootController存在
  2. 覆寫pointInside:withEvent:判斷事件所屬UIWindow
  3. 完善自己的事件命中測試眼虱,實(shí)現(xiàn)視圖層級管理

詳情參加Flex寫法。

模擬點(diǎn)擊

通過了解分析事件分發(fā)過程席纽,我們能很清楚的知道要實(shí)現(xiàn)模擬點(diǎn)擊我們只需把點(diǎn)擊事件發(fā)送給UIApplication單例的隊(duì)列就可以了捏悬。

  1. 創(chuàng)建UIEvent對象。
  2. 發(fā)送UIEvent對象[[UIApplication sharedApplication] sendEvent:event]润梯。

統(tǒng)計(jì)與修改UITouch

  1. hook UIApplication類的- (void)sendEvent:(UIEvent *)event;方法
  2. 進(jìn)行統(tǒng)計(jì)或修改

注:創(chuàng)建UITouch對象和對UITouch對象進(jìn)行修改过牙,可以參考kif-framework

參考資料

  1. flex
  2. kif-framework
  3. using responders and the responder chain to handle events
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纺铭,一起剝皮案震驚了整個(gè)濱河市寇钉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌舶赔,老刑警劉巖扫倡,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異竟纳,居然都是意外死亡撵溃,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門锥累,熙熙樓的掌柜王于貴愁眉苦臉地迎上來缘挑,“玉大人,你說我怎么就攤上這事桶略∮锾裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵际歼,是天一觀的道長惶翻。 經(jīng)常有香客問我,道長蹬挺,這世上最難降的妖魔是什么维贺? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮巴帮,結(jié)果婚禮上溯泣,老公的妹妹穿的比我還像新娘虐秋。我一直安慰自己,他們只是感情好垃沦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布客给。 她就那樣靜靜地躺著,像睡著了一般肢簿。 火紅的嫁衣襯著肌膚如雪靶剑。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天池充,我揣著相機(jī)與錄音桩引,去河邊找鬼。 笑死收夸,一個(gè)胖子當(dāng)著我的面吹牛坑匠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播卧惜,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼厘灼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了咽瓷?” 一聲冷哼從身側(cè)響起设凹,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎茅姜,沒想到半個(gè)月后闪朱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡钻洒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年监透,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片航唆。...
    茶點(diǎn)故事閱讀 40,096評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖院刁,靈堂內(nèi)的尸體忽然破棺而出糯钙,到底是詐尸還是另有隱情,我是刑警寧澤退腥,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布任岸,位于F島的核電站,受9級特大地震影響狡刘,放射性物質(zhì)發(fā)生泄漏享潜。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一嗅蔬、第九天 我趴在偏房一處隱蔽的房頂上張望剑按。 院中可真熱鬧疾就,春花似錦、人聲如沸艺蝴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽猜敢。三九已至姑荷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間缩擂,已是汗流浹背鼠冕。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留胯盯,地道東北人懈费。 一個(gè)月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像陨闹,于是被迫代替她去往敵國和親楞捂。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評論 2 355

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

  • 重點(diǎn)參考鏈接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi閱讀 4,452評論 0 15
  • 好奇觸摸事件是如何從屏幕轉(zhuǎn)移到APP內(nèi)的趋厉?困惑于Cell怎么突然不能點(diǎn)擊了寨闹?糾結(jié)于如何實(shí)現(xiàn)這個(gè)奇葩響應(yīng)需求?亦或是...
    Lotheve閱讀 57,149評論 51 599
  • 在iOS開發(fā)中經(jīng)常會涉及到觸摸事件君账。本想自己總結(jié)一下繁堡,但是遇到了這篇文章乡数,感覺總結(jié)的已經(jīng)很到位椭蹄,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 6,011評論 4 26
  • 本質(zhì)上是鄉(xiāng)下人净赴,他的根绳矩,他的魂不在城里,笨拙玖翅、遲鈍的標(biāo)簽盡顯翼馆。本是簡單純真的人,哪能適應(yīng)城里人復(fù)雜狡詐的人際關(guān)系金度?...
    小小佘閱讀 285評論 0 1
  • 一应媚、概念 二、代碼
    liyuhong閱讀 206評論 0 0