hitTest事件传递

564 阅读2分钟

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

  • 往下传递(superview):return nil
  • 往上传弟(subview):returen [super hitTest:point withEvent:event];
  • 自己消化,停止传递:return self

情况一

  • [黄色view addSubview:白色view]
  • 添加4个粉色button:[白色view addSubview:粉色button]
  • 白色view中有一些pink button可以点击
  • 但是如果触摸事件发生在白色view的空白区域,则需要把事件往下传递到黄色view

image.png

// 白色view重写该方法,以便实现触摸空白区域时,可以将触摸事件往下传递。self就是白色view
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *pinkButton in self.subviews) {
        CGPoint convertPoint = [self convertPoint:point toView:pinkButton];
        if (CGRectContainsPoint(pinkButton.bounds, convertPoint)) {
            // pinkButton可以接收这个事件,则需要让这个事件继续hitTest(往上)
            return [super hitTest:point withEvent:event];
        }
    }
    
    return nil; // 无子视图接收这个事件,自己也不需要接收这个事件,返回nil,这便传递到了黄色区域
}

情况二

情况背景和要求:

  • 因为某些极端场景的效率要求,越少添加触摸事件,效率越高;
  • 因为代码比较陈旧,粉色方框是用UIView一个一个的布局上的,而非使用collectionView
  • 点击任意粉色方框可以触发同一个action:pinkAction
  • 点击白色背景要求触摸事件可以传递到黄色视图(或者称之为事件穿透)
  • 如何只在白色视图上添加一个触摸事件,即可以达到这个效果。 image.png
/// 白色视图需要重写 hitTest:withEvent:
@interface WYWhiteView : UIView
@end

@implementation WYWhiteView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *pinkview in self.pinkViews) {
        CGPoint convertPoint = [self convertPoint:point toView:pinkview];
        if (CGRectContainsPoint(pinkview.bounds, convertPoint)) {
            // 点击在了pinkview范围内,则自己消化这次点击事件
            return self;
        }
    }
    return nil; // 点击在其它空白地方,则不接收这次点击事件
}
@end

TODO

  • 如何解释 pointInside 不能否完成这件事
  • 是否还有其它方式完成这件事?

一些其它参考