核心1. 介绍
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event point :
在接收器的局部坐标系(界)中指定的点。 event : 系统保证调用此方法的事件。
如果从事件处理代码外部调用此方法,则可以指定nil。 returnValue : 视图对象是当前视图和包含点的最远的后代。
如果点完全位于接收方的视图层次结构之外,则返回nil。
目的在于 : 在视图的层次结构中寻找一个最适合的 view 来响应触摸事件。
核心2.
调用顺序:touch -> UIApplication -> UIWindow -> UIViewController.view -> subViews -> ....-> 合适的view
事件传递顺序:view -> superView ...- > UIViewController.view -> UIViewController -> UIWindow -> UIApplication -> 事件丢弃
扩展1. subview超出fatherView的bounds仍然需要响应点击事件
/*
Case1: 点击button1 & button2 不在self的区域都有效
*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//1.判断自己能否接收事件
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
return nil;
}
// 这里无需判断point是否在父View的bounds内,因为middleButton和rightButton部分区域超出的父View
for (UIView *subview in [self.subviews reverseObjectEnumerator]) {
CGPoint convertedPoint = [subview convertPoint:point fromView:self];
UIView *hitTestView = [subview hitTest:convertedPoint withEvent:event];
if (hitTestView) {
return hitTestView;
}
}
return self;
}
/*
Case2: 点击button1不在self的区域《无》效
点击button2不在self的区域《有》效
*/
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//1.判断自己能否接收事件
if(self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
return nil;
}
CGPoint newPoint = [self convertPoint:point toView:button2];
if ([button2 pointInside:newPoint withEvent:event]) {
return button2;
}
return [super hitTest:point withEvent:event];
}
参考资料:https://blog.csdn.net/qq_18505715/article/details/78411052