如何等待重复的CAAnimation完成一个周期后再将其移除

5

我有一个视图,我使用CAAnimation来让它跳动。

CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
animation.values = @[ @0.0f, @1.0f, @0.0f ];
animation.duration = 0.5;
animation.repeatCount = HUGE_VALF;

[view.layer addAnimation:animation forKey:@"pulsate"];

当我使用[view.layer removeAnimationForKey:@"pulsate"]来移除动画时,不透明度会立即恢复。我想要实现的是当前正在执行的脉动动画完成后再移除动画。
我尝试将repeatCount设置为1,但这会抛出异常,因为动画是不可变的。
我也尝试从呈现层中获取当前值,并将其应用于模型,然后删除动画并再次添加动画以完成它。但这样在停止动画时会有明显的抽搐,并且通常时间不准确。
有没有办法让动画完成一次循环再将其移除?
1个回答

6

有很多细节需要注意,但总的想法是创建一个非重复动画,在完成后将其删除,然后使用 animationDidStop 代理方法重新启动动画。

首先要声明一些属性。

@property (weak, nonatomic) IBOutlet UIImageView *orangeView2;
@property (nonatomic) bool pulseActive;
@property (strong, nonatomic) CAKeyframeAnimation *pulseAnimation;

第一个属性是需要进行动画处理的视图,第二个属性用于跟踪动画是否已启用,最后一个属性是实际的动画(存储在属性中,以便我们只需实例化一次)。
接下来,我们将使用延迟实例化来创建动画对象。
- (CAKeyframeAnimation *)pulseAnimation
{
    if ( !_pulseAnimation )
    {
        _pulseAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
        _pulseAnimation.values = @[ @0.0f, @1.0f, @0.0f ];
        _pulseAnimation.duration = 0.5;

        _pulseAnimation.delegate = self;
        [_pulseAnimation setValue:@"PulseAnimation" forKey:@"AnimationIdentifier"];
    }

    return( _pulseAnimation );
}

重要的部分如下:
  • 默认情况下,动画不会重复播放。
  • 默认情况下,动画会在完成后被移除。
  • delegate 设置为 self,以便调用 animationDidStop 方法。
  • 使用 setValue:forKey: 为动画设置标识符。
如果多个动画使用相同的委托,则需要最后一项。在这种情况下,您需要一种方法来确定哪个动画调用了 animationDidStop。传递给 forKeysetValue 的字符串是任意的,并存储在动画对象的字典中。
现在我们需要实现 animationDidStop。该实现检查 pulseActive 属性,并在必要时重新启动动画(在检查动画的身份后)。
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
    NSString *animationIdentifier = [animation valueForKey:@"AnimationIdentifier"];

    if ( [animationIdentifier isEqualToString:@"PulseAnimation"] )
    {
        if ( self.pulseActive )
            [self.orangeView2.layer addAnimation:self.pulseAnimation forKey:@"pulsate"];
    }
}

现在要做的就是开始和停止动画。例如,一个可以切换动画的按钮。

- (IBAction)pulseButtonPressed
{
    if ( !self.pulseActive )
    {
        self.pulseActive = YES;
        [self.orangeView2.layer addAnimation:[self pulseAnimation] forKey:@"pulsate"];
    }
    else
    {
        self.pulseActive = NO;
    }
}

1
对我来说,重复使用动画并没有按预期工作,但是添加一个新的动画完美地解决了问题。谢谢! - Alfonso

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