核心动画 - 未调用 animationDidStop

Posted

技术标签:

【中文标题】核心动画 - 未调用 animationDidStop【英文标题】:Core Animation - animationDidStop not called 【发布时间】:2014-10-26 12:12:24 【问题描述】:

那里。

ios 应用中,Core 动画回调不起作用。

- (void)startAnim 
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    anim.fromValue = startAngle;
    anim.toValue = endAngle;
    anim.duration = 2;
    anim.delegate = self;

    [self.target addAnimation:anim forKey:nil];   // self.target is CALayer instance, it's sublayer of Custom UIView


- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag 
   [self.target setValue:@(endAngle) forKeyPath:@"transform.rotation.z"];

但 animationDidStop 永远不会被调用。 如果我将代码更改如下,则会调用完成阻塞。

- (void)startAnim 
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    anim.fromValue = startAngle;
    anim.toValue = endAngle;
    anim.duration = 2;
    anim.delegate = self;

    [CATransaction begin];
    [CATransaction setCompletionBlock:^
        [self.target setValue:@(endAngle) forKeyPath:@"transform.rotation.z"];
    ];

    [self.target addAnimation:anim forKey:nil];
    [CATransaction commit];

但我不想使用 CATransaction。 为什么不调用 animationDidStop?

更新: 有一种方法可以设置最终值,例如

- (void)startAnim 
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    anim.fromValue = startAngle;
    anim.toValue = endAngle;
    anim.duration = 2;
    anim.delegate = self;

    [self.target setValue:@(endAngle) forKeyPath:@"transform.rotation.z"];
    [self.target addAnimation:anim forKey:nil];

但最终分配应该在动画完成后完成。因为layer有多个动态动画,所以不知道最终值。

【问题讨论】:

你的动画真的在运行吗?我在UIView 层上的空UIViewController 中尝试完全相同的代码,并且animationDidStop:finished: 被正确调用。 我建议您重新考虑,我实际上建议您在添加动画时更新模型值。该值将始终反映您所追求的价值,并最终将达到。如果涉及“多个动态动画”,我可能会考虑使用“附加”动画或使用byValue 来避免必须跟踪明确的往返值。对于多个动画,您将获得多个 didStop 回调,并且在那里做正确的事情最终可能会变得更加复杂且难以维护。 使用 CATransaction 有什么问题? 【参考方案1】:

我找到了未调用 animationDidStop 的原因。

因为动画是在其他线程的循环中添加的,

所以我固定如下。

- (void)startAnim 
    dispatch_async(dispatch_get_main_queue(), ^
        CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        anim.fromValue = startAngle;
        anim.toValue = endAngle;
        anim.duration = 2;
        anim.delegate = self;

        [self.target addAnimation:anim forKey:nil];
    );

【讨论】:

也解决了我的问题!谢谢!【参考方案2】:

在我看来,您不希望动画重置其位置,这很简单,在设置动画时只需几行代码即可实现。

它可以像这样轻松地放置在您的代码中:

anim.fillMode = kCAFillModeForwards; anim.removedOnCompletion = NO;

这意味着当您的动画完成时,它将保留在最后,并且任何进一步的动画都将从该状态开始。

【讨论】:

是的,但我的动画没那么简单。有大量的动态动画,动画完成后应该删除它们。【参考方案3】:

去年我使用 UIView 的动画而不是 CABasicAnimation,但是如果我的记忆没有失败,你必须在添加动画之前设置 endAngle,所以试试这个:

- (void)startAnim 
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    anim.fromValue = startAngle;
    anim.toValue = endAngle;
    anim.duration = 2;
    anim.delegate = self;

    [self.target setValue:@(endAngle) forKeyPath:@"transform.rotation.z"];
    [self.target addAnimation:anim forKey:nil];

UPD:

你在开始动画之前设置anim.toValue = endAngle;,所以动画完成后结束值改变是不好的。无论如何,您可以在animationDidStop中重新设置它

- (void)startAnim 
    CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    anim.fromValue = startAngle;
    anim.toValue = endAngle;
    anim.duration = 2;
    anim.delegate = self;

    intermediateAngle = endAngle;

    [self.target setValue:@(endAngle) forKeyPath:@"transform.rotation.z"];
    [self.target addAnimation:anim forKey:nil];


- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag 
   if (intermediateAngle != endAngle) 
      startAngle = intermediateAngle;
      [self startAnim]; // or just [self.target setValue:@(endAngle) forKeyPath:@"transform.rotation.z"];
   

【讨论】:

我知道这种方式,但最终分配应该在动画完成时完成。因为layer有多个动态动画,所以不知道最终值。 animationDidStop 永远不会被调用,现在 你没有必须设置fromValueendValue(或者byValue)。这完全取决于您如何配置动画,与该键路径的模型值相比。

以上是关于核心动画 - 未调用 animationDidStop的主要内容,如果未能解决你的问题,请参考以下文章

核心动画警告:“未提交的 CATransaction”

核心动画立即调用完成函数

动画中断时未调用 UIView 动画完成块

动画期间未调用 CALayer setPosition

iOS:动画期间未调用 IBAction

动画期间未调用 UIButton 的选择器方法