iOS事件傳遞機制詳解
阿新 • • 發佈:2018-11-07
概述
- 當用戶觸控實際螢幕時,會生成一個Touch Event,將此事件新增到UIApplication管理的事件佇列之中。
- UIApplication從事件佇列之中按順序取出事件分發到檢視去處理。
- 當事件被髮出以後,會從keyWindow開始,依次向上傳遞,包括Controller以及View,最後找到合適的檢視來響應事件。
事件傳遞順序
涉及到兩個方法:
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;(以下簡稱hitTest)
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; (以下簡稱pointInside)
當UIApplication傳送事件到keyWindow時,會呼叫
hitTest
來尋找最合適的檢視處理事件。判斷邏輯如下:
- 首先判斷自身是否能夠響應觸控事件
(userInteractionEnabled==NO、hidden==YES、alpha<=0.01不能響應觸控事件)
,則hitTest
返回nil。 - 如果可以響應觸控事件,呼叫
pointInside
來判斷是否在顯示區域內,如果不在其中,pointInside
hitTest
返回nil。 - 如果
pointInside
返回YES,表示在當前的檢視之中,然後倒序(劃重點)
遍歷該檢視的子檢視,重複上述步驟,知道某一檢視可以響應,hitTest:
返回該檢視。 - 如果執行完上述步驟以後,沒有符合條件的檢視響應事件,則返回檢視本身,表示只有當前檢視符合條件,能夠處理該事件。
Talk is cheap, show me the code.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//步驟1
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
return nil;
}
//步驟2
if (![self pointInside:point withEvent:event]) {
return nil;
}
//步驟3
NSInteger subViewCount = self.subviews.count;
for (NSInteger i = subViewCount - 1; i >= 0; i--) {
UIView *subView = self.subviews[i];
CGPoint childPoint = [self convertPoint:point toView:subView];
UIView *hitView = [subView hitTest:childPoint withEvent:event];
if (hitView) {
return hitView;
}
}
//步驟4
return self;
}