一、什么是事件傳遞
發(fā)生觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的事件隊(duì)列中,并將事件分發(fā)下去以便處理。通常,會(huì)先發(fā)送事件給應(yīng)用程序的keyWindow,主窗口會(huì)在其視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件,這個(gè)找尋的過程就是事件傳遞。
二、事件傳遞的過程
1.事件傳遞的方向。
window -> 父視圖 -> 子視圖 - >子視圖的子視圖
我們可以這個(gè)方向簡單理解成從內(nèi)到外。-
2.兩個(gè)關(guān)鍵函數(shù)
首先我們先來了解兩個(gè)系統(tǒng)函數(shù)。
1.pointInside:withEvent:- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event;
這個(gè)方法是UIView用來判斷點(diǎn)擊事件發(fā)生的位置是否在當(dāng)前視圖范圍內(nèi)。
2.hitTest:withEvent:
// point是該視圖的坐標(biāo)系上的點(diǎn) - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { // 1.判斷自己能否接收觸摸事件 if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil; // 2.判斷觸摸點(diǎn)在不在自己范圍內(nèi) if (![self pointInside:point withEvent:event]) return nil; // 3.從后往前遍歷自己的子控件,看是否有子控件更適合響應(yīng)此事件 int count = self.subviews.count; for (int i = count - 1; i >= 0; i--) { UIView *childView = self.subviews[i]; CGPoint childPoint = [self convertPoint:point toView:childView]; UIView *fitView = [childView hitTest:childPoint withEvent:event]; if (fitView) { return fitView; } } // 沒有找到比自己更合適的view return self; }
以上是hitTest:withEvent:的底層實(shí)現(xiàn),這個(gè)方法在內(nèi)部總共會(huì)經(jīng)過三個(gè)步驟:
1.首先會(huì)判斷該視圖是否能響應(yīng)觸摸事件,如果不能響應(yīng),返回nil,表示該視圖不響應(yīng)此觸摸事件。
2.調(diào)用pointInside:withEvent:(該方法用來判斷點(diǎn)擊事件發(fā)生的位置是否處于當(dāng)前視圖范圍內(nèi))。如果pointInside:withEvent:返回NO,那么hiteTest:withEvent:也直接返回nil。
3.如果pointInside:withEvent:返回YES,則向當(dāng)前視圖的所有子視圖發(fā)送hitTest:withEvent:消息,所有子視圖的遍歷順序是從最頂層視圖一直到到最底層視圖,即從subviews數(shù)組的末尾向前遍歷。(這個(gè)遍歷的過程可理解為從外到里)直到有子視圖返回非空對(duì)象或者全部子視圖遍歷完畢;
若第一次有子視圖返回非空對(duì)象,則 hitTest:withEvent:方法返回此對(duì)象,該對(duì)象再繼續(xù)1,2,3的步驟;
若所有子視圖都返回非,則hitTest:withEvent:方法返回該視圖自身,說明事件傳遞到此結(jié)束,已經(jīng)找到了最合適的視圖來處理觸摸事件。
三、響應(yīng)者鏈
響應(yīng)者:繼承UIResponder的對(duì)象稱之為響應(yīng)者對(duì)象,能夠處理touchesBegan等觸摸事件。
響應(yīng)者鏈:由很多響應(yīng)者鏈接在一起組合起來的一個(gè)鏈條稱之為響應(yīng)者鏈條
每個(gè)能執(zhí)行hitTest:方法的view都屬于事件傳遞的一部分,但是,只有pointInside返回YES的view才屬于響應(yīng)者鏈條
通過事件傳遞找到最合適的處理觸摸事件的view后,它就是第一響應(yīng)者。所以事件傳遞是自下而上,而響應(yīng)者鏈?zhǔn)亲陨隙碌摹#╳indow上最外面的那個(gè)view稱為上)
四、實(shí)際應(yīng)用
1、擴(kuò)大響應(yīng)范圍;
2、根據(jù)響應(yīng)者鏈找到當(dāng)前的controller;
3、截獲事件,讓需要的view去響應(yīng)這個(gè)事件;
等等。