事件響應(yīng)和響應(yīng)者鏈

iOS 的事件主要分為以下幾類:

Touch Events(觸摸事件)

Motion Events(運(yùn)動(dòng)事件,比如重力感應(yīng)蛤奥、搖一搖等)

Remote Events(遠(yuǎn)程事件 缅刽,比如用耳機(jī)上的事件來(lái)控制手機(jī))

事件傳遞中UIWindow會(huì)根據(jù)不同的event,用不同的方式尋找initial object,initial object決定于當(dāng)前的事件類型微姊。比如Touch Event配喳,UIWindow會(huì)首先試著把事件傳遞給事件發(fā)生的那個(gè)view,就是下文要說(shuō)的hit-testview涧团。對(duì)于Motion和Remote Event预厌,UIWindow會(huì)把例如震動(dòng)或者遠(yuǎn)程控制的事件傳遞給當(dāng)前的firstResponder。

注:以下只討論觸摸事件

響應(yīng)者鏈(Responder chain)

響應(yīng)者對(duì)象是指能夠?qū)τ脩艚换ナ录M(jìn)行響應(yīng)的對(duì)象鞠绰,響應(yīng)者鏈?zhǔn)怯梢幌盗许憫?yīng)者對(duì)象構(gòu)成順序鏈。整個(gè)app就通過(guò)nextResponder串成了一條鏈灶壶,也就是我們所說(shuō)的響應(yīng)鏈担扑。所以響應(yīng)鏈就是一條虛擬的鏈燕垃,并沒(méi)有一個(gè)對(duì)象來(lái)專門(mén)存儲(chǔ)這樣的一條鏈低矮,而是通過(guò)UIResponder的屬性串連起來(lái)的蝗锥。

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

事件的產(chǎn)生

發(fā)生觸摸事件后穴张,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中玻驻,為什么是隊(duì)列而不是棧嗤锉,是因?yàn)殛?duì)列是先進(jìn)先出,而棧是先進(jìn)后出,先產(chǎn)生的事件應(yīng)該先處理玫氢。

UIApplication會(huì)從事件隊(duì)列中取出最前面的事件牢屋,并將事件分發(fā)下去以便處理,通常事件先發(fā)送給應(yīng)用程序的主窗口(keyWindow)鼓择。

主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來(lái)處理觸摸事件夷野,這也是整個(gè)事件處理過(guò)程的第一步铸豁。找到合適的視圖控件后,就會(huì)調(diào)用視圖控件的touches方法來(lái)作具體的事件處理。

事件的傳遞

觸摸事件的傳遞是從父視圖傳遞到子視圖的咙轩,即UIApplication->Window->尋找處理事件最合適的view

如果父視圖不能接收觸摸事件,那么子視圖就不可能接收到觸摸事件软棺。

如何找到最合適的視圖(Hit-Testing View)來(lái)處理事件

1.首先判斷視圖是否可以接受觸摸事件

2.判斷觸摸點(diǎn)是否在視圖上

3.子視圖數(shù)組中從后往前遍歷喘落,重復(fù)前面兩個(gè)操作

4.如果沒(méi)有符合條件的子視圖赌朋,那么就認(rèn)為自己是最合適的事件處理者,也就是最合適的視圖

UIView不能接收觸摸事件的三種情況

不允許交互:userInterationEnable = NO

隱藏:如果把父視圖隱藏逾冬,那么子視圖也會(huì)隱藏,隱藏的視圖不能接收觸摸事件

透明度:如果設(shè)置一個(gè)視圖的透明度<=0.01,則該視圖不能接收觸摸事件

如何判斷觸摸點(diǎn)是否在視圖上

Hit-Test 機(jī)制

當(dāng)用戶觸摸(Touch)屏幕進(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ì)通過(guò)hitTest:withEvent:方法尋找觸碰點(diǎn)所在的視圖溅呢,這個(gè)過(guò)程稱之為hit-test view澡屡。

那么什么是Hit-Test呢,我們可以把它理解為一個(gè)探測(cè)器咐旧,通過(guò)這個(gè)探測(cè)器我們可以找到并判斷手指是否點(diǎn)擊在某個(gè)視圖上面驶鹉,換句話說(shuō)就是通過(guò)Hit-Test可以找到手指點(diǎn)擊到的處于屏幕最前面的那個(gè)UIView。

在解釋Hit-Test是怎么工作之前铣墨,先來(lái)看看它是什么時(shí)候被調(diào)用的室埋。前面說(shuō)Hit-Test是一個(gè)探測(cè)器,那么在代碼里面其實(shí)就是一個(gè)函數(shù)伊约,UIView有如下兩個(gè)方法:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;

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

每當(dāng)手指接觸屏幕姚淆,UIApplication接收到手指的事件之后,就會(huì)去調(diào)用UIWindow的hitTest:withEvent:屡律,看看當(dāng)前點(diǎn)擊的點(diǎn)是不是在window內(nèi)腌逢,如果是則繼續(xù)依次調(diào)用subView的hitTest:withEvent:方法,直到找到最后需要的view超埋。調(diào)用結(jié)束并且hit-test view確定之后搏讶,這個(gè)view和view上面依附的手勢(shì),都會(huì)和一個(gè)UITouch的對(duì)象關(guān)聯(lián)起來(lái)霍殴,這個(gè)UITouch會(huì)作為事件傳遞的參數(shù)之一媒惕,我們可以看到UITouch頭文件里面有一個(gè)view和gestureRecognizers的屬性,就是hitTest view和它的手勢(shì)来庭。

hitTest 的順序如下

UIApplication -> UIWindow -> Root View -> ··· -> subview

在視圖上調(diào)用pointInside:withEvent:方法判斷觸摸點(diǎn)是否在當(dāng)前視圖內(nèi)妒蔚;

如果返回NO,那么hitTest:withEvent:返回nil月弛;

如果返回YES肴盏,那么它會(huì)從后往前遍歷子視圖數(shù)組執(zhí)行上述操作,直到有子視圖返回非空對(duì)象或者全部子視圖遍歷完畢尊搬。

如果有subview的hitTest:withEvent:返回非空對(duì)象叁鉴,則處理結(jié)束(注意這個(gè)過(guò)程,子視圖也是根據(jù)pointInside:withEvent:的返回值來(lái)確定是返回空還是當(dāng)前子視圖對(duì)象的佛寿。并且這個(gè)過(guò)程中如果子視圖的hidden=YES幌墓、userInteractionEnabled=NO或者alpha小于等于0.01都會(huì)并忽略);

如果所有subview遍歷結(jié)束仍然沒(méi)有返回非空對(duì)象冀泻,則hitTest:withEvent:返回self常侣;

系統(tǒng)就是這樣通過(guò)hit test找到觸碰到的視圖(Initial View)進(jìn)行響應(yīng)。

有了事件響應(yīng)鏈弹渔,接下來(lái)的事情就是尋找響應(yīng)事件的具體響應(yīng)者了胳施,我們稱著為:Hit-Testing View,尋找這個(gè)View的過(guò)程我們稱著為Hit-Test肢专。

響應(yīng)者鏈順序如下:

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

如果一個(gè)View有一個(gè)視圖控制器(View Controller)舞肆,它的下一個(gè)響應(yīng)者是這個(gè)視圖控制器焦辅,緊接著才是它的父視圖(Super View),如果一直到Root View都沒(méi)有處理這個(gè)事件椿胯,事件會(huì)傳遞到UIWindow(iOS中有一個(gè)單例Window)筷登,此時(shí)Window如果也沒(méi)有處理事件,便進(jìn)入U(xiǎn)IApplication哩盲,UIApplication是一個(gè)響應(yīng)者鏈的終點(diǎn)前方,它的下一個(gè)響應(yīng)者指向nil,以結(jié)束整個(gè)循環(huán)

事件傳遞的完整過(guò)程

先將事件對(duì)象由上往下傳遞(由父控件傳遞給子控件)廉油,找到最合適的控件來(lái)處理這個(gè)事件惠险。 調(diào)用最合適控件的touches….方法 如果調(diào)用了[super touches….];就會(huì)將事件順著響應(yīng)者鏈條往上傳遞,傳遞給上一個(gè)響應(yīng)者 接著就會(huì)調(diào)用上一個(gè)響應(yīng)者的touches….方法抒线。(如果視圖不能處理接收到的事件或者消息班巩,就會(huì)沿著響應(yīng)者鏈向上傳遞直到能夠響應(yīng)該事件的視圖,如果都不能響應(yīng)則舍棄)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘶炭,一起剝皮案震驚了整個(gè)濱河市趣竣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旱物,老刑警劉巖遥缕,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異宵呛,居然都是意外死亡单匣,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)宝穗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)户秤,“玉大人,你說(shuō)我怎么就攤上這事逮矛〖牛” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵须鼎,是天一觀的道長(zhǎng)鲸伴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)晋控,這世上最難降的妖魔是什么汞窗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮赡译,結(jié)果婚禮上仲吏,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好裹唆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布誓斥。 她就那樣靜靜地躺著,像睡著了一般许帐。 火紅的嫁衣襯著肌膚如雪岖食。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天舞吭,我揣著相機(jī)與錄音,去河邊找鬼析珊。 笑死羡鸥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的忠寻。 我是一名探鬼主播惧浴,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奕剃!你這毒婦竟也來(lái)了衷旅?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤纵朋,失蹤者是張志新(化名)和其女友劉穎柿顶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體操软,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嘁锯,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了聂薪。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片家乘。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖藏澳,靈堂內(nèi)的尸體忽然破棺而出仁锯,到底是詐尸還是另有隱情,我是刑警寧澤翔悠,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布业崖,位于F島的核電站,受9級(jí)特大地震影響蓄愁,放射性物質(zhì)發(fā)生泄漏腻要。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一涝登、第九天 我趴在偏房一處隱蔽的房頂上張望雄家。 院中可真熱鬧,春花似錦、人聲如沸趟济。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)顷编。三九已至戚炫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間媳纬,已是汗流浹背双肤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留钮惠,地道東北人茅糜。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像素挽,于是被迫代替她去往敵國(guó)和親蔑赘。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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