CAAnimation 在 CALayer 上没有按预期工作

Posted

技术标签:

【中文标题】CAAnimation 在 CALayer 上没有按预期工作【英文标题】:CAAnimation not working as expected on CALayer 【发布时间】:2015-02-22 10:59:46 【问题描述】:

我正在尝试为 CAShapeLayer 中的 UIBezierPath 的外观和消失设置动画。

我想做的是,在开始时,通过将 strokeStartstrokeEnd 设置为 0,路径将不可见。然后,在我的 animate 方法中,我将执行 CABasicAnimation 并设置strokeEnd 为 1,完成此操作后,另一个动画我将 strokeStart 设置为 1,因此路径将再次消失。这是我尝试过的:

- (void)animate

    CAShapeLayer *layer = (CAShapeLayer *)self.layer;

    CABasicAnimation *appearingAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    appearingAnimation.duration = _duration / 2.0;
    appearingAnimation.fromValue = @0;
    appearingAnimation.toValue = @1;

    CABasicAnimation *disappearingAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
    disappearingAnimation.beginTime = _duration / 2.0;
    disappearingAnimation.duration = _duration / 2.0;
    disappearingAnimation.fromValue = @0;
    disappearingAnimation.toValue = @1;

    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    animationGroup.duration = _duration;
    animationGroup.animations = @[appearingAnimation, disappearingAnimation];
    animationGroup.repeatCount = MAXFLOAT;
    [layer addAnimation:animationGroup forKey:@"test"];

但我看到的效果是appearingAnimation 工作正常,但是一旦完成,路径立即消失,没有任何动画。在此之后(_duration/2.0 时间之后)整个事情重新开始,所以看起来disappearingAnimation 没有效果。

我尝试了另一种方法,但只有当路径在我的view.layer 上时才有效。当我将它添加到子图层并尝试为那个子图层设置动画时,第二个(消失的)动画出现了故障。这是我的第二种方法:

- (void)animate

    CAShapeLayer *layer = (CAShapeLayer *)self.layer;

    layer.strokeStart = 0;
    layer.strokeEnd = 1;

    [CATransaction begin];
    [CATransaction setCompletionBlock:^
        layer.strokeStart = 1;
        layer.strokeEnd = 1;

        [CATransaction begin];
        [CATransaction setCompletionBlock:^
             [self animate];
        ];

        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
        animation.duration = _duration / 2.0;
        animation.fromValue = [NSNumber numberWithDouble:0];
        animation.toValue = [NSNumber numberWithDouble:1];
        [layer addAnimation:animation forKey:@"animation1"];
        [CATransaction commit];
    ];
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.duration = _duration / 2.0;
    animation.fromValue = [NSNumber numberWithDouble:0];
    animation.toValue = [NSNumber numberWithDouble:1];
    [layer addAnimation:animation forKey:@"animation"];
    [CATransaction commit];

知道为什么第一个解决方案根本不起作用,或者为什么第二个解决方案只能在view.layer 而不是sublayer 上正常工作吗?

【问题讨论】:

【参考方案1】:

在为图层属性设置动画时,您需要在添加动画之前将图层属性设置为结束值,因为动画更改仅应用于演示文稿,而不应用于模型图层。一旦动画完成,它将被移除,使图层保持之前的状态。

一旦创建了层(从您的 sn-p 中丢失),您概述的第一种和第二种方法都对我有用:

- (void)animate

    CAShapeLayer *layer = [CAShapeLayer layer];
    CGFloat _duration = 2.0;
    CGFloat radius = self.view.frame.size.width/2.0;
    CGFloat startAngle = -(M_PI_2);
    CGFloat endAngle = (3*M_PI_2);
    CGPoint center = CGPointMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0);

    layer.path = [[UIBezierPath bezierPathWithArcCenter:center
                                                 radius:radius
                                            startAngle:startAngle
                                               endAngle:endAngle
                                              clockwise:YES] CGPath];
    layer.fillColor = [[UIColor clearColor] CGColor];
    layer.strokeColor = [[UIColor blackColor] CGColor];
    [self.view.layer addSublayer:layer];

   ... animation code

【讨论】:

【参考方案2】:

我认为是_duration / 2.0的值的问题。可能是浮点数计算的问题。

尽量不要将总时长减半,而是将appearingAnimationdisappearingAnimation的时长作为基础时长:

#define DURATION_BASE 1
// You can choose the DURATION_BASE value whaterver you like

- (void)animate

    CAShapeLayer *layer = (CAShapeLayer *)self.layer;

    CABasicAnimation *appearingAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    appearingAnimation.duration = DURATION_BASE;
    appearingAnimation.fromValue = @0;
    appearingAnimation.toValue = @1;

    CABasicAnimation *disappearingAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
    disappearingAnimation.beginTime = appearingAnimation.duration;
    disappearingAnimation.duration = DURATION_BASE;
    disappearingAnimation.fromValue = @0;
    disappearingAnimation.toValue = @1;

    CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
    animationGroup.duration = appearingAnimation.duration+disappearingAnimation.duration;
    animationGroup.animations = @[appearingAnimation, disappearingAnimation];
    animationGroup.repeatCount = MAXFLOAT;
    [layer addAnimation:animationGroup forKey:@"test"];

当你想改变appearingAnimationdisappearingAnimation的持续时间,你只需要修改代码

appearingAnimation.duration = DURATION_BASE*1.2;

disappearingAnimation.duration = DURATION_BASE*1.2;

【讨论】:

以上是关于CAAnimation 在 CALayer 上没有按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

CALayer (CAAnimation) 动画属性绘制错误

键-值编码扩展

带有 timeRange 的 CAAnimation - iOS

CAAnimation - 显示/隐藏持续时间为 0

CAAnimation - 更改动画最后一帧的属性?

Core Animation 文档翻译—附录C(KVC扩展)