iOS动画演示文稿层命中测试似乎没有按预期工作

时间:2016-08-09 09:42:31

标签: ios objective-c core-animation calayer

我正在尝试将触摸事件添加到从屏幕右侧向左侧漂移的小视图块。问题是layer.presentationLayer hitTest:point方法没有返回任何内容,即使我确实在视图块的范围内进行了挖掘。

最后,我找到了解决方法。但是,两个问题仍然让我感到困惑。

  1. 转换后的点似乎不对,如何正确使用presentationLayer hitTest
  2. 在我的代码段中,UIViewAnimationOptionAllowUserInteraction未设置,为什么我还能处理触摸事件?
  3. 以下是代码,任何帮助将不胜感激

    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
    

1 个答案:

答案 0 :(得分:1)

  

Q1:转换后的点似乎不对,如何正确使用presentationLayer hitTest?

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

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

Q2:在我的代码片段中,未设置UIViewAnimationOptionAllowUserInteraction,为什么我可以处理触摸事件

我认为您可以获取触摸事件,因为您覆盖- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event并返回self作为结果,因此事件将传递给它。默认情况下(如果不覆盖hitTest:withEvent:方法),则不会触及事件。

如果你设置UIViewAnimationOptionAllowUserInteraction选项,你可以在视图的最后一帧(CGRectMake(-40,200,40,40))上获得触摸事件,但在这个例子中,最后一帧不在屏幕上,您可以将其设置为CGRectMake(0, 200, 40, 40)并进行测试。