圆形遮罩视图动画过快且无法点击。

4
我正在尝试创建一个带有动画蒙版的圆形图片视图,并尝试了不同的解决方案。下面的示例可以完成任务,但是我遇到了两个问题:
1)为什么我无法使图片可点击?例如添加UITapGestureRecognizer不起作用。我猜测蒙版阻止了触摸操作传播到视图层次结构中较低的级别。
2)蒙版的动画运行得非常快,我无法使用UIView块动画调整持续时间。
如何解决这些问题?
- (void) addCircle {
    // this is the encapsulating view
    //
    base = [[UIView alloc] init];
    //
    // this is the button background
    //
    base_bgr = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"c1_bgr.png"]];
    base_bgr.center = CGPointMake(60, 140);
    [base addSubview:base_bgr];
    //
    // icon image
    //
    base_icon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"c1_ico.png"]];
    base_icon.center = CGPointMake(186*0.3/2, 182*0.3/2);
    base_icon.transform = CGAffineTransformMakeScale(0.3, 0.3);
    [base addSubview:base_icon];
    //
    // the drawn circle mask layer
    //
    circleLayer = [CAShapeLayer layer];
    // Give the layer the same bounds as your image view
    [circleLayer setBounds:CGRectMake(0.0f, 0.0f, [base_icon frame].size.width,
                                      [base_icon frame].size.height)];
    // Position the circle
    [circleLayer setPosition:CGPointMake(186*0.3/2-7, 182*0.3/2-10)];
    // Create a circle path.
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:
                          CGRectMake(0.0f, 0.0f, 70.0f, 70.0f)];
    // Set the path on the layer
    [circleLayer setPath:[path CGPath]];

    [[base layer] setMask:circleLayer];

    [self.view addSubview:base];
    base.center = CGPointMake(100, 100);
    base.userInteractionEnabled = YES;
    base_bgr.userInteractionEnabled = YES;
    base_icon.userInteractionEnabled = YES;

    //
    // NOT working: UITapGestureRecognizer
    //
    UITapGestureRecognizer *tapgesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapit:)];
    [base_icon addGestureRecognizer:tapgesture];

    //
    // BAD but WORKS :) properly positioned UIButton over the masked image
    //
    base_btn = [UIButton buttonWithType:UIButtonTypeCustom];
    base_btn.frame = CGRectMake(base.frame.origin.x, base.frame.origin.y, base_icon.frame.size.width, base_icon.frame.size.height);
    [base_btn addTarget:self action:@selector(tapit:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:base_btn];
}

这是触摸事件处理程序,这里是遮罩动画。无论我尝试使用的持续时间为多少,它都会快速播放 - 大约0.25秒,并且我无法调整它。
- (void) tapit:(id) sender {
    //...
        [UIView animateWithDuration:1.0
                              delay:0.0
                            options:UIViewAnimationOptionCurveEaseOut
                         animations:^ {
                             [circleLayer setTransform:CATransform3DMakeScale(10.0, 10.0, 1.0)];
                         }
                         completion:^(BOOL finished) {
                             // it is not necessary if I manage to make the icon image tappable
                             base_btn.frame = [base convertRect:base_icon.frame toView:self.view];  
                         }];
    }    
}

如果Base没有被触发,tapit怎么可能会被调用呢? - Unheilig
1个回答

1

1) touches事件不会从base向下传递,因为它是在没有框架的情况下启动的,所以它的框架将是CGRectZero。视图不会接收到从其边界外开始的触摸事件。只需在base上设置一个包含整个点击目标的有效框架即可。

2) 对层进行setTransform:操作会调用隐式动画,该动画使用Core Animation的默认持续时间0.25(你猜对了:))。最好的解决方案是使用CABasicAnimation而不是基于UIView的动画。像这样:

CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
scaleAnimation.toValue = @(10.0f);
scaleAnimation.duration = 2;
[circleLayer addAnimation:scaleAnimation forKey:nil];

注意:默认情况下,CABasicAnimation 完成后会从图层中移除,并且图层会回到旧值。例如可以通过将该动画的 removedOnCompletion 属性设置为 NO 并稍后使用 CALayerremoveAnimationForKey: 方法手动删除它(只需设置一个键而不是传递 nil 添加动画),但这取决于您要实现什么样的效果。

1
测试过并且可行,谢谢!我的经验是关于保持CABasicAnimation最后一个阶段的,我还必须包括fillMode = kCAFillModeForwards; - nzs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接