一、提綱html
二、事件分發機制app
2.一、來源ide
以直接觸摸事件爲例:spa
如何找處處理這個事件的視圖的過程——事件分發機制代理
2.二、具體步驟code
2.2.一、事件Event的產生htm
點擊一下iOS設備的屏幕,UIKit就會生成一個事件對象UIEvent,而後會把這個Event分發給當前活動的app; 對象
當前活動的app得知有事件,UIApplication 單例就會從事件隊列中去取最新的事件,而後分發給可以處理該事件的對象(具體視圖)。blog
2.2.二、運用到的兩個UIView中的方法繼承
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event; //找到並返回最合適的視圖來 - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; //判斷點是否在視圖內
當一個視圖View收到hitTest消息時,會調用本身的poinInside方法;
若是返回YES,View會遍歷本身的子視圖(遍歷順序先addSubView先遍歷),子視圖就會調用本身的hitTest方法;
若是返回NO,View就不會遍歷本身子視圖(很節約);
直到找到最小的可以處理事件的view,若是整了一圈沒找到可以處理的view,則返回自身。
2.2.三、舉例說明
白色:ViewController , 綠色:一個View視圖 , 藍色:一個Button按鈕
現象:點擊綠色視圖內的按鈕區域,正常;點擊綠色視圖外的按鈕區域,按鈕的selector方法不會調用?
從新綠色view的hitTest方法:
點擊有效區域時:返回視圖座標{{88, -26}, {47, 52}},此座標是相對父視圖的;
點擊區域外的部分時:返回視圖座標{{0, 0}, {0, 0}},因此按鈕不會響應;
從新hitTest方法,修改返回view,當點擊區域外按鈕部分時也返回有效視圖{{88, -26}, {47, 52}},如圖所示;
另一種解決方案:更暴力
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{ return YES; }
號外:
1. UIView 的 nextResponder 是直接管理它的 UIViewController (也就是 VC.view.nextResponder = VC ),若是當前 View 不是 ViewController 直接管理的 View,則 nextResponder 是它的 superView( view.nextResponder = view.superView )。 2. UIViewController 的 nextResponder 是它直接管理的 View 的 superView( VC.nextResponder = VC.view.superView )。 若是viewcontroller的view是window的根view,那麼下一個響應者是window; 若是viewcontroller是另外一個viewcontroller模態推出的,那麼下一個響應者是另外一個viewcontroller; 若是viewcontroller的view被add到另外一個viewcontroller的根view上,那麼下一個響應者是另外一個viewcontroller的根view 3. UIWindow 的 nextResponder 是 UIApplication 。 4. UIApplication 的 nextResponder 是 AppDelegate。
通常來講,某個 UIResponder 的子類想要本身處理一些事件,就須要重寫它的這些方法(觸摸爲例):
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event; - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event; - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event; - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event; - (void)touchesEstimatedPropertiesUpdated:(NSSet<UITouch *> *)touches NS_AVAILABLE_IOS(9_1);
若是想本身處理後,繼續讓事件響應下去:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; } - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; } - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; } - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { [super touchesBegan:touches withEvent:event]; }
四、手勢對響應鏈有何影響
手勢識別器並非響應者鏈中的一員,可是手勢識別器會觀察touch事件,並延遲事件向所綁定的視圖傳遞;
在上例中給Button和view添加點擊手勢:
按鈕會優先響應手勢,而不是自身的selector;
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{ if ([touch.view isKindOfClass:[UIButton class]]) { return NO; }else{ return YES; } }
添加手勢又屏蔽:有毛病?
在其餘UICollectionView和UIScrollView、UITableView等,若是須要在視圖上添加手勢,cell上也會響應手勢,此方法能夠解決手勢和自身方法的衝突!