iOS--子视图如何穿透上层视图响应事件

一、使用方法:
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;

二.背景知识
iOS系统检测到手指触摸(Touch)操作时会将其放入当前活动Application的事件队列,Application会从事件队列中取出触摸事件并传递给key window(当前接收用户事件的窗口)处理,window对象首先会使用hitTest:withEvent:方法寻找此次Touch操作初始点所在的视图(View),即需要将触摸事件传递给其处理的视图,称之为hit-test view。
window对象会在首先在view hierarchy的顶级view上调用hitTest:withEvent:,此方法会在视图层级结构中的每个视图上调用pointInside:withEvent:,如果pointInside:withEvent:返回YES,则继续逐级调用,直到找到touch操作发生的位置,这个视图也就是hit-test view。
三、处理流程
1.首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内;
2.若返回NO,则hitTest:withEvent:返回nil;
3.若返回YES,则向当前视图的所有子视图(subviews)发送hitTest:withEvent:消息,所有子视图的遍历顺序是从
top到bottom,即从subviews数组的末尾向前遍历,直到有子视图返回非空对象或者全部子视图遍历完毕;
4.若第一次有子视图返回非空对象,则hitTest:withEvent:方法返回此对象,处理结束;
5.如所有子视图都返回非,则hitTest:withEvent:方法返回自身(self)。
四、代码示例

// 在父视图中实现方法
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
// 1.这是当前点击的视图,如果没有找到合适的响应操作的视图,则直接返回这个
UIView *view = [super hitTest:point withEvent:event];

// 2.将父视图坐标转成我想要响应事件的视图的坐标
CGPoint buttonPoint = [self convertPoint:point toView:self.button];

// 3.判断该坐标是否在视图内部,如果是,则返回该视图
if ([self.button pointInside:buttonPoint withEvent:event]) {
return self.button;
}
return view;
}

五、注意事项
1.设置hidden = YES;仍然是可以通过该方法响应事件。
2.设置alpha = 0.001;也是可以通过该方法响应事件。
3.子视图的 origin 即使超出父视图的范围也是可以响应事件。
4.设置userInteractionEnabled = NO;则不可以响应事件了。

  

by:lm

原文地址:https://www.cnblogs.com/widgetbox/p/lm.html