什么时候调用:当事件传递给当前View时, 会调用当前Veiw的hitTest方法;
作用:寻找最适合的View.
返回值:返回谁,谁就是最适合的view,谁就响应事件,就会调用谁的touches方法
在上一篇提到事件传递过程中如何找到最合适的View来处理触摸事件,分为四步:
1.判断自己能否接收事件
2.点在不在自己身上
3.从后往前遍历自己了的子控件,把事件传递给子控件,调用子控件的hitTest,
4.如果子控件没有找到最适合的View,那么自己就是最适合的View.
如果需要重写hitTest方法,这4个步骤是必须的:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//1.判断自己能否接收事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) {
//不能接收事件
return nil;
}
//2.点在不在自己身上
if (![self pointInside:point withEvent:event]) {
return nil;
}
//3.从后往前遍历自己的子控件,把事件传递给子控件,调用子控件的hitTest,
int count = (int)self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
//获取子控件
UIView *childView = self.subviews[i];
//把当前点的坐标系转换成子控件的坐标系
CGPoint childP = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childP withEvent:event];
if (fitView) {
return fitView;
}
}
//4.如果子控件没有找到最适合的View,那么自己就是最适合的View.
return self;
}
其中判断点在不在自己身上,系统提供了一个pointInside:
方法,会在hitTest内部调用该方法。
注意:必须得要跟方法调用者在同一个坐标系
可以看到在上面hitTest内部实现代码中, 有一个转换坐标系的操作,就是为了点和方法调用这在同一个坐标系中。
//把当前点的坐标系转换成子控件的坐标系
CGPoint childP = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childP withEvent:event];
hitTest的应用
怎么办到点击黄色view和Button重叠部分让Button响应点击?
分析:hitTest
方法的作用就是找到最合适的View来响应点击事件,如果按正常流程走的话,点击重叠部分,肯定是黄色View来响应该点击事件,只需要重写黄色View的hitTest
方法,判断如果点击在重叠部分,就返回红色Button即可。
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
//判断点在不在红色按钮身上, 如果在,直接返回红色按钮
CGPoint redP = [self convertPoint:point toView:self.redBtn];
if ([self.redBtn pointInside:redP withEvent:event]) {
return self.redBtn;
}
//否则保持原有做法.
return [super hitTest:point withEvent:event];
}