ios 響應(yīng)鏈

首先清楚兩個(gè)概念
響應(yīng)者:對(duì)用戶交互動(dòng)作事件進(jìn)行響應(yīng)的對(duì)象。
響應(yīng)者鏈:成為處理事件的響應(yīng)者的先后順序鏈沥割。
平時(shí)當(dāng)我們點(diǎn)擊屏幕的時(shí)候耗啦,操作系統(tǒng)把包含點(diǎn)擊事件的信息包裝成UITouch和UIEvent形式的實(shí)例,然后找到當(dāng)前運(yùn)行的程序机杜,逐級(jí)尋找能夠響應(yīng)這個(gè)事件的對(duì)象帜讲,直到?jīng)]有響應(yīng)者響應(yīng)。這個(gè)尋找過程椒拗,就叫做事件的響應(yīng)鏈似将,如下圖所示


1452653940101147.png

當(dāng)一個(gè)常見的用戶事件發(fā)生的時(shí)候,UIKit會(huì)創(chuàng)建一個(gè)事件對(duì)象Event Object蚀苛,該對(duì)象包含了事件處理所必須的一些信息在验。然后它會(huì)將事件對(duì)象置于激活的app事件隊(duì)列。
一堵未、Hit-Test機(jī)制
當(dāng)用戶觸摸屏幕進(jìn)行交互時(shí)腋舌,系統(tǒng)首先要找到響應(yīng)者(Responder)。系統(tǒng)檢測(cè)到手指觸摸(Touch)操作時(shí)兴溜,將Touch以UIEvent的方式加入U(xiǎn)IApplication事件隊(duì)列中侦厚。UIApplication從事件隊(duì)列中取出最新的觸摸事件進(jìn)行分發(fā)傳遞到UIWindow進(jìn)行處理耻陕。UIWindow會(huì)通過hitTestL:withEvent:方法尋找觸碰點(diǎn)所在的視圖拙徽,這個(gè)過程被稱之為hit-test-view(命中測(cè)試view)。
使用hit-testing去尋找觸摸發(fā)生下的view诗宣。命中測(cè)試會(huì)執(zhí)行檢測(cè)判斷是否該觸摸點(diǎn)發(fā)生在某個(gè)具體的view的相對(duì)邊界之內(nèi)膘怕。如果檢測(cè)是的,它就會(huì)遞歸傳遞的去檢測(cè)該view的所有子view召庞。該view的層級(jí)最底端view包含觸摸點(diǎn)岛心,它就成為“命中測(cè)試view”。之后iOS就會(huì)遞交觸摸事件給它處理篮灼。
舉例說明:如下圖

652024-27b51a71f8a42474.png

1.檢測(cè)觸摸點(diǎn)是否在view A的邊界之內(nèi)忘古,如果是它會(huì)檢測(cè)子視圖B和C。
2.觸摸點(diǎn)不在view B的邊界之內(nèi)诅诱,但是它在view C的邊界之內(nèi)髓堪,因此它就去檢測(cè)C的子視圖D和E。
3.觸摸事件不在view D的邊界之內(nèi),但是在view E的邊界之內(nèi)干旁。view E是整個(gè)包含觸摸事件的view層級(jí)中最底端的view驶沼,因此view E就成為hit-test-view。

其檢測(cè)方法是:方法hitTest:withEvent傳入CGPoint和UIEvent返回“命中測(cè)試view”争群。這個(gè)方法hitTest:withEvent開始執(zhí)行通過調(diào)用自身的pointInside:withEvent方法回怜。如果傳入hitTest:withEvent的point在view的邊界之內(nèi)。pointInside:withEvent方法就會(huì)返回YES换薄。然后該方法會(huì)遞歸調(diào)用hitTest:withEvent方法在每一個(gè)返回YES的子view上玉雾。

如果傳入的hitTest:withEvent的點(diǎn)不在view的邊界之內(nèi),首先會(huì)調(diào)用ponitInside:withEvent方法返回NO,該point會(huì)被忽略轻要,并且hitTest:withEvent返回nil(注意這個(gè)過程抹凳,子視圖也是根據(jù)pointInside:withEvent:的返回值來確定是返回空還是當(dāng)前子視圖對(duì)象的。并且這個(gè)過程中如果子視圖的hidden=YES伦腐、userInteractionEnabled=NO或者alpha小于0.1都會(huì)并忽略)赢底,如果一個(gè)子view返回NO,那么整個(gè)view層級(jí)的分支都會(huì)被忽略柏蘑,因?yàn)槿绻|摸點(diǎn)沒有發(fā)生在子view幸冻,她也不可能發(fā)生在任何子view的子view。這就意味著任何子view上面的點(diǎn)都在邊界之外并且它的父view也不能接受觸摸事件咳焚,因?yàn)橛|摸點(diǎn)必須同時(shí)在父view和子view的邊界之內(nèi)洽损。這種情況可能會(huì)發(fā)生,如果子view的 clipsToBound 屬性設(shè)為NO革半。
二 碑定、響應(yīng)者鏈
有些時(shí)候,Touch后系統(tǒng)通過hit test 機(jī)制找到了觸碰到的Initial View又官,但是Initial view并沒有或者無法正常處理此次Touch延刘。這個(gè)時(shí)候,系統(tǒng)便會(huì)通過響應(yīng)者鏈尋找下一個(gè)響應(yīng)者六敬,以對(duì)此次Touc 進(jìn)行響應(yīng)碘赖。

Initial View -> View Controller(如果存在) -> superview -> · ·· -> rootView -> UIWindow -> UIApplication


1467190622568169.jpg

如果一個(gè)View有一個(gè)視圖控制器(View Controller),它的下一個(gè)響應(yīng)者是這個(gè)試圖控制器外构,緊接著才是它的父視圖(super view)普泡,如果一直到Root View都沒有處理這個(gè)事件,事件會(huì)傳遞到UIWindow(iOS中有個(gè)單例Window)审编,此時(shí)Window如果也沒有處理事件撼班,便進(jìn)入U(xiǎn)IApplication,UIApplication是一個(gè)響應(yīng)者鏈的終點(diǎn)垒酬,它的下一個(gè)響應(yīng)者指向nil砰嘁,以結(jié)束整個(gè)循環(huán)眯亦。

在某些情景下,我們?cè)邳c(diǎn)擊子視圖的時(shí)候仍然需要調(diào)用父視圖的touchesBegan:withEvent:等方法般码,例如我們?cè)诟敢晥D上添加了一個(gè)覆蓋范圍了父視圖大部分面積的TableView或ScrollerView 或其他View妻率,而我們要通過父視圖的touchesBegan:withEvent:方法來收鍵盤。
這個(gè)時(shí)候我們可以通過UIView的類別板祝,重寫touch相關(guān)方法宫静,代碼如下:
-(void)setEnableNextResponder:(BOOL)enableNextResponder {
objc_setAssociatedObject(self, &enableNextResponderKey, enableNextResponderKey, OBJC_ASSOCIATION_ASSIGN);
}
-(BOOL)enableNextResponder {
return objc_getAssociatedObject(self, &enableNextResponderKey);
}
-(void)touchesBegan:(NSSet<uitouch *> *)touches withEvent:(UIEvent *)event{
if (self.enableNextResponder) {
[[self nextResponder] touchesBegan:touches withEvent:event];
[super touchesBegan:touches withEvent:event];
}
}
-(void)touchesEnded:(NSSet<uitouch *> *)touches withEvent:(UIEvent *)event {
if (self.enableNextResponder) {
[[self nextResponder] touchesEnded:touches withEvent:event];
[super touchesEnded:touches withEvent:event];
}
}
-(void)touchesMoved:(NSSet<uitouch *> *)touches withEvent:(UIEvent *)event {
if (self.enableNextResponder) {
[[self nextResponder] touchesMoved:touches withEvent:event];
[super touchesMoved:touches withEvent:event];
}
}
-(void)touchesCancelled:(NSSet<uitouch *> *)touches withEvent:(UIEvent *)event {
if (self.enableNextResponder) {
[[self nextResponder] touchesCancelled:touches withEvent:event];
[super touchesCancelled:touches withEvent:event];
}
}</uitouch *></uitouch *></uitouch *></uitouch *>
三、響應(yīng)鏈應(yīng)用
重寫PointInside
可以通過重寫查找事件處理者的方法來實(shí)現(xiàn)不規(guī)則形狀點(diǎn)擊券时。最常見的不規(guī)則視圖就是圓形視圖孤里,在demo中我設(shè)置view的寬高為200,那么重寫方法事件如下:

A76C394D-01D6-49B5-A093-CBA68E6709C6.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末橘洞,一起剝皮案震驚了整個(gè)濱河市捌袜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炸枣,老刑警劉巖虏等,帶你破解...
    沈念sama閱讀 221,695評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異适肠,居然都是意外死亡霍衫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門侯养,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敦跌,“玉大人,你說我怎么就攤上這事逛揩∧” “怎么了?”我有些...
    開封第一講書人閱讀 168,130評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵辩稽,是天一觀的道長(zhǎng)惧笛。 經(jīng)常有香客問我,道長(zhǎng)搂誉,這世上最難降的妖魔是什么徐紧? 我笑而不...
    開封第一講書人閱讀 59,648評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮炭懊,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拂檩。我一直安慰自己侮腹,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,655評(píng)論 6 397
  • 文/花漫 我一把揭開白布稻励。 她就那樣靜靜地躺著父阻,像睡著了一般愈涩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上加矛,一...
    開封第一講書人閱讀 52,268評(píng)論 1 309
  • 那天履婉,我揣著相機(jī)與錄音,去河邊找鬼斟览。 笑死毁腿,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的苛茂。 我是一名探鬼主播已烤,決...
    沈念sama閱讀 40,835評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼妓羊!你這毒婦竟也來了胯究?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤躁绸,失蹤者是張志新(化名)和其女友劉穎裕循,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體净刮,經(jīng)...
    沈念sama閱讀 46,286評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡费韭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,375評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庭瑰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片星持。...
    茶點(diǎn)故事閱讀 40,505評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖弹灭,靈堂內(nèi)的尸體忽然破棺而出督暂,到底是詐尸還是另有隱情,我是刑警寧澤穷吮,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布逻翁,位于F島的核電站,受9級(jí)特大地震影響捡鱼,放射性物質(zhì)發(fā)生泄漏八回。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,873評(píng)論 3 333
  • 文/蒙蒙 一驾诈、第九天 我趴在偏房一處隱蔽的房頂上張望缠诅。 院中可真熱鬧,春花似錦乍迄、人聲如沸管引。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽褥伴。三九已至谅将,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間重慢,已是汗流浹背饥臂。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留似踱,地道東北人隅熙。 一個(gè)月前我還...
    沈念sama閱讀 48,921評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像屯援,于是被迫代替她去往敵國(guó)和親猛们。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,515評(píng)論 2 359

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