ios中的響應(yīng)者鏈-Responder Chain

響應(yīng)者鏈工作原理

應(yīng)用程序使用Responder對(duì)象接收和處理時(shí)間,響應(yīng)者對(duì)象是UIResponder類的任何實(shí)例,常見的子類包括UIViewUIViewControllerUIApplication.響應(yīng)者收到原始事件數(shù)據(jù),并且必須處理該事件或?qū)⑵滢D(zhuǎn)發(fā)給另一個(gè)響應(yīng)者對(duì)象,當(dāng)您的應(yīng)程序收到一個(gè)事件時(shí),UIKit會(huì)自動(dòng)將該事件指向最合適的響應(yīng)者對(duì)象,稱為第一響應(yīng)者,未處理的事件從響應(yīng)者傳遞到活動(dòng)響應(yīng)器中的響應(yīng)者,這是應(yīng)用程序的響應(yīng)者對(duì)象的動(dòng)態(tài)配置,應(yīng)用程序中沒有單個(gè)響應(yīng)者鏈,UIKit定義了將對(duì)象從一個(gè)響應(yīng)者傳遞到下一個(gè)響應(yīng)器的默認(rèn)規(guī)則,但是您可以隨時(shí)通過覆蓋響應(yīng)者對(duì)象中相對(duì)應(yīng)的屬性來(lái)更改這些規(guī)則.下圖顯示了應(yīng)用程序的默認(rèn)響應(yīng)者鏈,其界面包含Label,textField,button和兩個(gè)背景視圖,如果label不處理事件,UIKit會(huì)將事件發(fā)送到其superView對(duì)象,然后是窗口的根視圖,從根視圖響應(yīng)者鏈轉(zhuǎn)移到擁有該視圖的控制器,然后將事件傳遞給window,如果window不處理,UIKit將事件傳遞給UIApplication對(duì)象,并且可能將該事件傳遞給AppDelegate,

1.png

對(duì)于每種類型的事件,UIKit指定一個(gè)第一響應(yīng)者,并首先發(fā)送事件到這個(gè)對(duì)象,第一響應(yīng)者根據(jù)事件的類型而有所不同.

  • Touch events
    第一響應(yīng)者是發(fā)生觸摸的視圖
  • Press events
    第一響應(yīng)者是有焦點(diǎn)的響應(yīng)者
  • Shake-motion events
    第一響應(yīng)者是(UIKit)指定為第一個(gè)響應(yīng)者的對(duì)象
  • Remote-control events
    第一響應(yīng)者是(UIKit)指定為第一個(gè)響應(yīng)者的對(duì)象
  • Editing menu messages
    第一響應(yīng)者是(UIKit)指定為第一個(gè)響應(yīng)者的對(duì)象

與加速器,陀螺儀和磁力計(jì)相關(guān)的運(yùn)動(dòng)事件不遵循響應(yīng)者連,Core Motion將這些事件直接傳遞給你指定的對(duì)象,(https://developer.apple.com/library/content/documentation/Miscellaneous/Conceptual/iPhoneOSTechOverview/CoreServicesLayer/CoreServicesLayer.html#//apple_ref/doc/uid/TP40007898-CH10-SW27)

當(dāng)手指觸摸到屏幕中,觸摸到某一個(gè)控件到響應(yīng)這個(gè)事件分為兩步:事件的傳遞與分發(fā),和事件的響應(yīng)
事件的傳遞涉及到UIView中的兩個(gè)方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
//判斷當(dāng)前點(diǎn)擊事件是否存在最優(yōu)響應(yīng)者(First Responder)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
//判斷當(dāng)前點(diǎn)擊是否在控件的Bounds之內(nèi) 

UIKit使用基于視圖的命中測(cè)試來(lái)確定觸摸事件發(fā)生的位置康谆。 具體來(lái)說柄慰,UIKit將觸摸位置與視圖層次結(jié)構(gòu)中的視圖對(duì)象的邊界進(jìn)行比較。 UIView的hitTest(_:with :)方法行進(jìn)視圖層次結(jié)構(gòu)哩都,尋找包含指定觸摸的最深的子視圖魁兼。 該視圖成為觸摸事件的第一響應(yīng)者

注意如果觸摸位置在視圖的邊界之外,則hitTest(_:with :)方法會(huì)忽略該視圖及其所有子視圖茅逮。 因此璃赡,當(dāng)視圖的clipsToBounds屬性為false時(shí),即使它們包含觸摸,也不會(huì)返回該視圖邊界之外的子視圖
事件的傳遞其實(shí)就是在事件產(chǎn)生于分發(fā)之后如何尋找最優(yōu)響應(yīng)的一個(gè)過程

你可以修改響應(yīng)者對(duì)象的next屬性來(lái)更改響應(yīng)者鏈,當(dāng)你修改了此屬性時(shí)下一個(gè)響應(yīng)者就是你返回的對(duì)象,
許多UIKit類已經(jīng)覆蓋此屬性并返回特定對(duì)象献雅。

  • UIView對(duì)象,如果這個(gè)控制器的View是根視圖,那么next responder 就是viewController,否則,就是這個(gè)view的父視圖

  • UIViewController對(duì)象,

    • 如果該controller的view是window的根視圖,那么next responder就是window
    • 如果controller是由另一個(gè)controller presented的,那么next responder是the presenting Controller.
  • UIWindow對(duì)象,next responder 就是UIApplication對(duì)象

  • UIApplication對(duì)象,那么 next responder 就是 app delegate ,但前提是appDelegateUIResponder的一個(gè)實(shí)例,而不是view,viewcontroller或者是app本身.


                                 (以上來(lái)自官方文檔)

事件的傳遞過程

1.觸碰屏幕產(chǎn)生事件UIEvent并存入UIApplication中事件隊(duì)列中,并在整個(gè)視圖結(jié)構(gòu)中自下而上進(jìn)行分發(fā),如下圖
2.UIWindow 接收到事件開始進(jìn)行最優(yōu)響應(yīng)視圖查詢過程(逆序遍歷子視圖)
3.當(dāng)?shù)?code>UiviewController這一層時(shí)同樣對(duì)其視圖開始最優(yōu)響應(yīng)視圖查詢,該查詢會(huì)調(diào)用上述提到的兩個(gè)方法,采用逆序查詢也是為了優(yōu)化查找速度,畢竟后添加的視圖易于命中

3831145-33ef2920581a014d.png

命中查找流程

1.調(diào)用hitTest方法進(jìn)行最優(yōu)響應(yīng)視圖查找

  • hidden = YES;
  • userInteractionEnabled = NO;
  • alpha < 0.01
    這三種情況hitTest方法會(huì)返回nil ,即當(dāng)前視圖下無(wú)最有相應(yīng)視圖,無(wú)法響應(yīng)事件

2.hitTest方法內(nèi)部調(diào)用pointInside方法對(duì)點(diǎn)擊進(jìn)行是否在當(dāng)前視圖bounds內(nèi)進(jìn)行判斷,如果超出bounds范圍,則hitTest返回nil,未超出范圍繼續(xù)步驟3
3.對(duì)當(dāng)前視圖下的subviews進(jìn)行逆序步驟1,2查詢最優(yōu)響應(yīng)者,如果hitTest返回視圖,則說明當(dāng)前視圖有最優(yōu)響應(yīng)者,可能是self也可能是subview,

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    
    if (self.alpha < 0.01 || !self.userInteractionEnabled || self.hidden) {
        
        return nil;
    }
    
    if (![self pointInside:point withEvent:event]) {
        
        return nil;
    }
    
    __block UIView *hitView = nil;
    [self.subviews enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIView * _Nonnull subview, NSUInteger idx, BOOL * _Nonnull stop) {
        
        hitView = [subview hitTest:point withEvent:event];
        if (hitView) {
            
            *stop = YES;
        }
    }];
    
    return hitView ? : self;
}

總結(jié)

  • 事件分發(fā)與傳遞:自上而下(UIApplication-window-.....)
  • 事件響應(yīng):自下而上(view-superView-.........)
3831145-8f25188c47eacafd.jpg

打印結(jié)果:


點(diǎn)擊CView

參考:http://www.reibang.com/p/eacb86714799.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碉考,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子挺身,更是在濱河造成了極大的恐慌侯谁,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件章钾,死亡現(xiàn)場(chǎng)離奇詭異墙贱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贱傀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門惨撇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人府寒,你說我怎么就攤上這事魁衙。” “怎么了株搔?”我有些...
    開封第一講書人閱讀 169,301評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵剖淀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我纤房,道長(zhǎng)纵隔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮捌刮,結(jié)果婚禮上碰煌,老公的妹妹穿的比我還像新娘。我一直安慰自己糊啡,他們只是感情好拄查,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著棚蓄,像睡著了一般堕扶。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梭依,一...
    開封第一講書人閱讀 52,682評(píng)論 1 312
  • 那天稍算,我揣著相機(jī)與錄音,去河邊找鬼役拴。 笑死糊探,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的河闰。 我是一名探鬼主播科平,決...
    沈念sama閱讀 41,155評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼姜性!你這毒婦竟也來(lái)了瞪慧?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,098評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤部念,失蹤者是張志新(化名)和其女友劉穎弃酌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體儡炼,經(jīng)...
    沈念sama閱讀 46,638評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妓湘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了乌询。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榜贴。...
    茶點(diǎn)故事閱讀 40,852評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妹田,靈堂內(nèi)的尸體忽然破棺而出竣灌,到底是詐尸還是另有隱情,我是刑警寧澤秆麸,帶...
    沈念sama閱讀 36,520評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站及汉,受9級(jí)特大地震影響沮趣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坷随,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評(píng)論 3 335
  • 文/蒙蒙 一房铭、第九天 我趴在偏房一處隱蔽的房頂上張望驻龟。 院中可真熱鬧,春花似錦缸匪、人聲如沸翁狐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)露懒。三九已至,卻和暖如春砂心,著一層夾襖步出監(jiān)牢的瞬間懈词,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工辩诞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坎弯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評(píng)論 3 379
  • 正文 我出身青樓译暂,卻偏偏與公主長(zhǎng)得像抠忘,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子外永,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評(píng)論 2 361

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

  • 用戶以多種方式操縱他們的iOS設(shè)備崎脉,例如觸摸屏幕或搖動(dòng)設(shè)備。 iOS會(huì)解釋用戶何時(shí)以及如何操作硬件并將此信息傳遞到...
    坤坤同學(xué)閱讀 4,001評(píng)論 7 19
  • 在iOS開發(fā)中經(jīng)常會(huì)涉及到觸摸事件象迎。本想自己總結(jié)一下荧嵌,但是遇到了這篇文章,感覺總結(jié)的已經(jīng)很到位砾淌,特此轉(zhuǎn)載啦撮。作者:L...
    WQ_UESTC閱讀 6,026評(píng)論 4 26
  • iOS開發(fā)中的事件處理 理論非原創(chuàng),是對(duì)網(wǎng)上資料的整理以及Demo驗(yàn)證 一. UIResponder 1.1 事件...
    喪心病狂樂閱讀 679評(píng)論 0 0
  • 好奇觸摸事件是如何從屏幕轉(zhuǎn)移到APP內(nèi)的?困惑于Cell怎么突然不能點(diǎn)擊了汪厨?糾結(jié)于如何實(shí)現(xiàn)這個(gè)奇葩響應(yīng)需求赃春?亦或是...
    Lotheve閱讀 57,338評(píng)論 51 599
  • 喬幫主在發(fā)布會(huì)上提到,用戶的手才是最好的輸入設(shè)備劫乱,的確织中,iPhone之后,非觸屏手機(jī)再已難覓衷戈。觸摸是最基本的用戶輸...
    皮皮Warrior閱讀 2,244評(píng)論 3 48