iOS UI事件傳遞與響應(yīng)者鏈

響應(yīng)者鏈

  • 響應(yīng)者對象:繼承自UIResponder的對象稱之為響應(yīng)者對象暇矫。UIApplication、UIWindow择吊、UIViewController和所有繼承UIView的UIKit類都直接或間接的繼承自UIResponder李根。
    UIResponder一般響應(yīng)以下幾種事件:觸摸事件(touch handling)、點按事件(press handling)几睛、加速事件和遠程控制事件:
觸摸事件(touch handling)
- (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;
- (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);
點按事件(press handling) NS_AVAILABLE_IOS(9_0)
- (void)pressesBegan:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesChanged:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesEnded:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
- (void)pressesCancelled:(NSSet<UIPress *> *)presses withEvent:(nullable UIPressesEvent *)event NS_AVAILABLE_IOS(9_0);
加速事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionEnded:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(3_0);
遠程控制事件
- (void)remoteControlReceivedWithEvent:(nullable UIEvent *)event NS_AVAILABLE_IOS(4_0);
  • 響應(yīng)者鏈:由多個響應(yīng)者組合起來的鏈條房轿,就叫做響應(yīng)者鏈。它表示了每個響應(yīng)者之間的聯(lián)系所森,并且可以使得一個事件可選擇多個對象處理


    響應(yīng)者鏈.png

    假設(shè)觸摸了initial view囱持,
    1.第一響應(yīng)者就是initial view即initial view首先響應(yīng)touchesBegan:withEvent:方法,接著傳遞給橘黃色的view
    2.橘黃色的view開始響應(yīng)touchesBegan:withEvent:方法焕济,接著傳遞給藍綠色view
    3.藍綠色view響應(yīng)touchesBegan:withEvent:方法纷妆,接著傳遞給控制器的view
    4.控制器view響應(yīng)touchesBegan:withEvent:方法,控制器傳遞給了窗口
    5.窗口再傳遞給application
    如果上述響應(yīng)者都不處理該事件啥刻,那么事件被丟棄

事件的產(chǎn)生和傳遞

當(dāng)一個觸摸事件產(chǎn)生的時候进萄,我們的程序是如何找到第一響應(yīng)者的呢浮禾?


事件的產(chǎn)生傳遞.png

當(dāng)你點擊了屏幕會產(chǎn)生一個觸摸事件,消息循環(huán)(runloop)會接收到觸摸事件放到消息隊列里际邻,UIApplication會會從消息隊列里取事件分發(fā)下去,首先傳給UIWindow芍阎,UIWindow會使用hitTest:withEvent:方法找到此次觸摸事件初始點所在的視圖枯怖,找到這個視圖之后他就會調(diào)用視圖的touchesBegan:withEvent:方法來處理事件。

  • hitTest:withEvent:查找過程


    hitTestview過程.png
圖片中view等級
    [ViewA addSubview:ViewB];
    [ViewA addSubview:ViewC];
    [ViewB addSubview:ViewD];
    [ViewB addSubview:ViewE];

點擊viewE:
1.A 是UIWindow的根視圖能曾,首先對A進行hitTest:withEvent:
2.判斷A的userInteractionEnabled度硝,如果為NO肿轨,A的hitTest:withEvent返回nil;
3.pointInside:withEvent:方法判斷用戶點擊是否在A的范圍內(nèi),顯然返回YES
4.遍歷A的子視圖B和C蕊程,由于從后向前遍歷椒袍,

  • 因此先查看C,調(diào)用C的hitTest:withEvent方法:pointInside:withEvent:方法判斷用戶點擊是否在C的范圍內(nèi)藻茂,不在返回NO驹暑,C對應(yīng)的hitTest:withEvent: 方法return nil;
  • 再查看B辨赐,調(diào)用B的hitTest:withEvent方法:pointInside:withEvent:判斷用戶點擊是否在B的返回內(nèi)优俘,在返回YES
    遍歷B的子視圖D和E,從后向前遍歷掀序,
    先查看E帆焕,調(diào)用E的hitTest:withEvent方法:pointInside:withEvent:方法 判斷用戶點擊是否在E的范圍內(nèi),在返回YES不恭,E沒有子視圖叶雹,因此E對應(yīng)的hitTest:withEvent方法返回E,再往前回溯,就是B的hitTest:withEvent方法返回E换吧,因此A的hitTest:withEvent方法返回E折晦。

至此,點擊事件的第一響應(yīng)者就找到了沾瓦。

如果hitTest:withEvent: 找到的第一響應(yīng)者view沒有處理該事件满着,那么事件會沿著響應(yīng)者鏈向上傳遞->父視圖->視圖控制器,如果傳遞到最頂級視圖還沒處理事件贯莺,那么就傳遞給UIWindow處理风喇,若window對象也不處理->交給UIApplication處理,如果UIApplication對象還不處理乖篷,就丟棄該事件响驴。

事件流程.png

注意:控件不能響應(yīng)的情況
1.userInteractionEnabled = NO
2.hidden = YES
3.透明度 alpha 小于等于0.01
4.子視圖超出了父視圖區(qū)域

子視圖超出父視圖,不響應(yīng)的原因:因為父視圖的pointInside:withEvent:方法返回了NO撕蔼,就不會遍歷子視圖了豁鲤。可以重寫pointInside:withEvent:方法解決此問題鲸沮。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末琳骡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子讼溺,更是在濱河造成了極大的恐慌楣号,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異炫狱,居然都是意外死亡藻懒,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門视译,熙熙樓的掌柜王于貴愁眉苦臉地迎上來嬉荆,“玉大人,你說我怎么就攤上這事酷含”稍纾” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵椅亚,是天一觀的道長限番。 經(jīng)常有香客問我,道長呀舔,這世上最難降的妖魔是什么弥虐? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮别威,結(jié)果婚禮上躯舔,老公的妹妹穿的比我還像新娘驴剔。我一直安慰自己省古,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布丧失。 她就那樣靜靜地躺著豺妓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪布讹。 梳的紋絲不亂的頭發(fā)上琳拭,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天,我揣著相機與錄音描验,去河邊找鬼白嘁。 笑死,一個胖子當(dāng)著我的面吹牛膘流,可吹牛的內(nèi)容都是我干的絮缅。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼呼股,長吁一口氣:“原來是場噩夢啊……” “哼耕魄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起彭谁,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤吸奴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體则奥,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡考润,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了读处。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片额划。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖档泽,靈堂內(nèi)的尸體忽然破棺而出俊戳,到底是詐尸還是另有隱情,我是刑警寧澤馆匿,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布抑胎,位于F島的核電站,受9級特大地震影響渐北,放射性物質(zhì)發(fā)生泄漏阿逃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一赃蛛、第九天 我趴在偏房一處隱蔽的房頂上張望恃锉。 院中可真熱鬧,春花似錦呕臂、人聲如沸破托。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽土砂。三九已至,卻和暖如春谜洽,著一層夾襖步出監(jiān)牢的瞬間萝映,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工阐虚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留序臂,地道東北人。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓实束,卻偏偏與公主長得像奥秆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子磕洪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,652評論 2 354

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