一、事件傳遞機制
在iOS中,只有繼承于UIResponder的子類,才可以處理事件。
1.當iOS程序中發生觸摸事件后,系統會將事件加入到UIApplication管理的一個任務隊列中
2.UIApplication將處于任務隊列最前端的事件向下分發。即UIWindow。
3.UIWindow將事件向下分發,即UIView。
4.UIView首先看自己是否能處理事件,觸摸點是否在自己身上。如果能,那么繼續尋找子視圖。
5.遍歷子控件,重復3,4兩步。如果沒有在子控件找到觸摸點,那么自己就是事件處理者。
6.如果自己不能處理觸摸響應,那么不做任何處理。
事件分發傳遞,以下三種情況是不做處理的:
1.alpha < 0.01
2.userInteractionEnabled = NO
3.hidden = YES
若父視圖事件不做處理,(以上三種情況),那么子視圖也不會傳遞事件,改事件傳遞被廢棄。
//此方法返回的view是本次點擊事件需要的最佳view
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
//判斷一個點是否在視圖范圍內
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
1.通過重寫hitTest方法,可將點擊的點移動到子view。
2.重寫pointInside方法,可擴大按鈕的點擊區域。
eg: 按鈕的點擊區域重寫,小于44*44做處理,大于不處理
下面示例是定義一個button的可點擊區域
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
CGRect bounds = self.bounds;
CGFloat widthDelta = MAX(44 - bounds.size.width, 0);
CGFloat heightDelta = MAX(44 - bounds.size.height, 0);
bounds = CGRectInset(bounds, -0.5 * widthDelta, -0.5 * heightDelta);
return CGRectContainsPoint(bounds, point);
}
二、事件響應鏈
1.事件響應鏈的響應剛好和事件傳遞相反,事件傳遞是從UIApplication管理起點,逐級向下傳遞。而響應鏈則從下向上傳遞。響應鏈是通過nextResponder屬性組成的一個鏈表,點擊的view有 superView,nextResponder就是superView;
image.png
最有機會處理事件的就是通過事件傳遞找到的 first responder,如果沒有進行處理,就會沿著事件響應鏈傳遞給下一個響應者 nextResponder,一直追溯到最上層 UIApplication。若都沒有進行處理,就丟棄事件。
處理事件
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
對于觸摸事件,系統提供了上面四種方法來處理。如果重寫了上述方法,那么事件就會在此中斷,并且不再沿著事件響應鏈進行傳遞;如果需要繼續進行傳遞,則需要調用 super 方法。