ios中的響應者鏈-Responder Chain

響應者鏈工作原理

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

1.png

對于每種類型的事件,UIKit指定一個第一響應者,并首先發送事件到這個對象,第一響應者根據事件的類型而有所不同.

  • Touch events
    第一響應者是發生觸摸的視圖
  • Press events
    第一響應者是有焦點的響應者
  • Shake-motion events
    第一響應者是(UIKit)指定為第一個響應者的對象
  • Remote-control events
    第一響應者是(UIKit)指定為第一個響應者的對象
  • Editing menu messages
    第一響應者是(UIKit)指定為第一個響應者的對象

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

當手指觸摸到屏幕中,觸摸到某一個控件到響應這個事件分為兩步:事件的傳遞與分發,和事件的響應
事件的傳遞涉及到UIView中的兩個方法

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
//判斷當前點擊事件是否存在最優響應者(First Responder)
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
//判斷當前點擊是否在控件的Bounds之內 

UIKit使用基于視圖的命中測試來確定觸摸事件發生的位置。 具體來說,UIKit將觸摸位置與視圖層次結構中的視圖對象的邊界進行比較。 UIView的hitTest(_:with :)方法行進視圖層次結構,尋找包含指定觸摸的最深的子視圖。 該視圖成為觸摸事件的第一響應者

注意如果觸摸位置在視圖的邊界之外,則hitTest(_:with :)方法會忽略該視圖及其所有子視圖。 因此,當視圖的clipsToBounds屬性為false時,即使它們包含觸摸,也不會返回該視圖邊界之外的子視圖
事件的傳遞其實就是在事件產生于分發之后如何尋找最優響應的一個過程

你可以修改響應者對象的next屬性來更改響應者鏈,當你修改了此屬性時下一個響應者就是你返回的對象,
許多UIKit類已經覆蓋此屬性并返回特定對象。

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

  • UIViewController對象,

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

  • UIApplication對象,那么 next responder 就是 app delegate ,但前提是appDelegateUIResponder的一個實例,而不是view,viewcontroller或者是app本身.


                                 (以上來自官方文檔)

事件的傳遞過程

1.觸碰屏幕產生事件UIEvent并存入UIApplication中事件隊列中,并在整個視圖結構中自下而上進行分發,如下圖
2.UIWindow 接收到事件開始進行最優響應視圖查詢過程(逆序遍歷子視圖)
3.當到UiviewController這一層時同樣對其視圖開始最優響應視圖查詢,該查詢會調用上述提到的兩個方法,采用逆序查詢也是為了優化查找速度,畢竟后添加的視圖易于命中

3831145-33ef2920581a014d.png

命中查找流程

1.調用hitTest方法進行最優響應視圖查找

  • hidden = YES;
  • userInteractionEnabled = NO;
  • alpha < 0.01
    這三種情況hitTest方法會返回nil ,即當前視圖下無最有相應視圖,無法響應事件

2.hitTest方法內部調用pointInside方法對點擊進行是否在當前視圖bounds內進行判斷,如果超出bounds范圍,則hitTest返回nil,未超出范圍繼續步驟3
3.對當前視圖下的subviews進行逆序步驟1,2查詢最優響應者,如果hitTest返回視圖,則說明當前視圖有最優響應者,可能是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;
}

總結

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

打印結果:


點擊CView

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內容

  • 用戶以多種方式操縱他們的iOS設備,例如觸摸屏幕或搖動設備。 iOS會解釋用戶何時以及如何操作硬件并將此信息傳遞到...
    坤坤同學閱讀 4,018評論 7 19
  • 在iOS開發中經常會涉及到觸摸事件。本想自己總結一下,但是遇到了這篇文章,感覺總結的已經很到位,特此轉載。作者:L...
    WQ_UESTC閱讀 6,062評論 4 26
  • iOS開發中的事件處理 理論非原創,是對網上資料的整理以及Demo驗證 一. UIResponder 1.1 事件...
    喪心病狂樂閱讀 713評論 0 0
  • 好奇觸摸事件是如何從屏幕轉移到APP內的?困惑于Cell怎么突然不能點擊了?糾結于如何實現這個奇葩響應需求?亦或是...
    Lotheve閱讀 57,664評論 51 601
  • 喬幫主在發布會上提到,用戶的手才是最好的輸入設備,的確,iPhone之后,非觸屏手機再已難覓。觸摸是最基本的用戶輸...
    皮皮Warrior閱讀 2,261評論 3 48