App通过responder object 来接收和处理事件, UIResponder是responder object的基类;包括UIView,UIWindow,UIWindow,UIApplication及他们的子类。
事件传递传递:
当我们触摸屏幕时, 该触摸时间会添加到UIApplication管理的事件队列(称为队列的原因时先进先出)中,按顺序取出最早事件(先进先出),通过下面方法找到所触摸的视图,
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event; // recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system
- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; // default returns YES if point is in bounds
具体使用如下(猜测,肯定不止这些内容)
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
if (!self.userInteractionEnabled || self.isHidden || self.alpha <= 0.01) {
return nil;
}
if ([self pointInside:point withEvent:event]) {
for (UIView *view in self.subviews) {
CGPoint convertedPoint = [view convertPoint:point fromView:self];
return [view hitTest:convertedPoint withEvent:event];
}
}
return nil;
}
userInteractionEnabled 不能交互 isHidden隐藏 alpha小于0.01的视图都不能响应,所以过滤掉。
具体传递顺序如下: UIWindow开始知道找到可以响应并且触摸点在View的bouns内的视图
响应链:
查看响应链
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[super touchesBegan:touches withEvent:event];
UIResponder *responder = self;
while (responder) {
NSLog(@"%@",responder.class);
responder = responder.nextResponder;
}
}
响应链如上图
UITextField不响应,找UITextField的parentView, 直到找到响应着为止
响应方法
- (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;