一、提纲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上也会响应手势,此方法能够解决手势和自身方法的冲突!