iOS animation presentationLayer hitTest 似乎没有按预期工作

iOS animation presentationLayer hitTest does not seem to work as expected

我正在尝试向从屏幕右侧漂移到左侧的小视图块添加触摸事件。问题是 layer.presentationLayer hitTest:point 方法 returns 什么都没有,即使我确实在视图块的范围内点击。

终于,我找到了解决方法。但是,有两个问题还是让我很困惑。

  1. 转换的点数好像不对,如何正确使用presentationLayer hitTest
  2. 在我的代码片段中,UIViewAnimationOptionAllowUserInteraction没有设置,为什么我仍然可以处理触摸事件?

代码如下,如有帮助将不胜感激

viewDidLoad

CGRect bounds = [[UIScreen mainScreen] bounds];

for (int i = 0; i < 15; i++) {

    ViewBlock *view = [[ViewBlock alloc] initWithFrame:CGRectMake(bounds.size.width, 200, 40, 40)];
    [self.view addSubview:view];


    [UIView animateWithDuration:20 delay:i * 21 options:UIViewAnimationOptionCurveLinear animations:^{
        view.frame = CGRectMake(-40, 200, 40, 40);
    } completion:^(BOOL finished) {
        [view removeFromSuperview];
    }];
}

ViewBlock.m

@implementation ViewBlock
- (instancetype)initWithFrame:(CGRect)frame{

    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor redColor];
    }
    return self;
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
    CALayer *presentationLayer = self.layer.presentationLayer; //Do NOT modify presentationLayer
    if (presentationLayer) {
        CGPoint layer_point = [presentationLayer convertPoint:point fromLayer:self.layer.modelLayer];
        if ([presentationLayer hitTest:point]) {
            return self; //not worked
        }

        if ([presentationLayer hitTest:layer_point]) {
            return self; //not worked either
        }

        if (CGRectContainsPoint(presentationLayer.bounds, layer_point)) {
            return self;  //the workaround
        }
    }
    return [super hitTest:point withEvent:event];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    [super touchesBegan:touches withEvent:event];
    NSLog(@"touches began");
}

- (void)didMoveToSuperview{
    [super didMoveToSuperview];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTouched:)]
    ;
    tap.cancelsTouchesInView = NO;

    [self addGestureRecognizer:tap];
}

- (void)tapTouched:(UITapGestureRecognizer *)sender{
    NSLog(@"touches gesture");
}
@end

Q1: The converted point does not seem to be right, how to properly use presentationLayer hitTest?

你缺少的是 hitTest: 的参数应该在接收者超层的坐标系中,所以代码应该是:

CGPoint superLayerP = [presentationLayer.superlayer convertPoint:layer_point fromLayer:presentationLayer];
if ([presentationLayer hitTest:superLayerP]) {
    return self;
}

Q2:In my code snippet, UIViewAnimationOptionAllowUserInteraction is not set, why I can handle touch event anyway

我认为您可以获得触摸事件,因为您覆盖了 - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 和 return self 作为结果,因此事件将传递给它。默认情况下(如果你不覆盖 hitTest:withEvent: 方法),你不会得到触摸事件。

如果你设置了UIViewAnimationOptionAllowUserInteraction选项,你可以在视图的最后一帧(CGRectMake(-40, 200, 40, 40))上获得触摸事件,但是在这个例子中,最后一帧是关闭的screen,可以设置成CGRectMake(0, 200, 40, 40)测试一下