核心动画 - 未调用 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 永远不会被调用,现在 你没有必须设置fromValue
和endValue
(或者byValue
)。这完全取决于您如何配置动画,与该键路径的模型值相比。以上是关于核心动画 - 未调用 animationDidStop的主要内容,如果未能解决你的问题,请参考以下文章