什么是事件傳遞
事件傳遞:在iOS系統(tǒng)中,事件可以分為三類:
public enum EventType : Int {
case touches // 觸摸事件
case motion // 運(yùn)動事件(比如重力感應(yīng)、搖一搖等等)
case remoteControl // 遠(yuǎn)程控制事件(比如可以用耳機(jī)控制手機(jī))
@available(iOS 9.0, *)
case presses
}
touch events 大多數(shù)都是相同的,并且在觸摸事件發(fā)生的時(shí)候會傳遞給view;
motion events 由UIKit觸發(fā),并且會由Core Motion framework區(qū)分motion events;
Rmote-control events 允許響應(yīng)對象接收來自 external accessory 或者 headset 的命令,這樣就可以管理音頻和視頻了;
Press events 表示 a game controller 和 AppleTV 或者 其他有物理按鍵的設(shè)備的遠(yuǎn)程事件之間的交互
事件的傳遞過程:主要針對的是touch events
當(dāng)我們觸摸屏幕的時(shí)候,為我們找到最合適的view。
每當(dāng)手機(jī)觸摸屏幕,操作系統(tǒng)會把事件傳遞給當(dāng)前的APP,在UIApplication接收到手指的事件之后,就會去調(diào)用 UIWindow 的 hitTest:withEvent: 方法,看看當(dāng)前點(diǎn)擊的點(diǎn)是不是在window內(nèi),如果是則繼續(xù)調(diào)用其subview的 hitTest:withEvent: 方法,直到找到最后需要的view。
hitTest:withEvent: 的內(nèi)部實(shí)現(xiàn)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (self.hidden || self.userInteractionEnabled == NO || self.alpha < 0.01 || [self pointInside:point withEvent:event]) {
return nil;
}
for (UIView *subView in self.subviews.reverseObjectEnumerator) {
UIView *hitView = [subView hitTest:[subView convertPoint:point fromView:self] withEvent:event];
if (hitView) {
return hitView;
}
}
return self;
}
什么是響應(yīng)過程
在事件傳遞過程中,找到事件響應(yīng)的view,控件調(diào)用 touch 的一系列方法,判斷是否實(shí)現(xiàn) touch 的一系列方法,如果沒有實(shí)現(xiàn),就將事件傳遞給上一個(gè)響應(yīng)者,如果最終找不到,方法作廢
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
如果有實(shí)現(xiàn)就由此View來響應(yīng),如果沒有實(shí)現(xiàn),那么就傳遞給他的下一個(gè)響應(yīng)者。
我的理解:

在開發(fā)中的應(yīng)用
1.攔截點(diǎn)擊事件
重寫父視圖的 hitTest:withEvent: 方法
2.擴(kuò)大點(diǎn)擊面積
// 方法一
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGRect rect = self.bounds;
rect = CGRectInset(rect, -30, -30); // 增加點(diǎn)擊面積
return CGRectContainsPoint(rect, point);
}
// 方法二
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGRect rect = self.bounds;
rect = CGRectInset(rect, -30, -30); // 增加點(diǎn)擊面積
if (CGRectContainsPoint(rect, point)) {
return self;
}
return nil;
}