Core Animation (CABasicAnimation) 的不可预测行为

Posted

技术标签:

【中文标题】Core Animation (CABasicAnimation) 的不可预测行为【英文标题】:Unpredictable behavior with Core Animation (CABasicAnimation) 【发布时间】:2012-10-09 10:37:00 【问题描述】:

我正在为 ios 编写一条线动画,其中一条线在 CALayer 上绘制为 CGPath 中的一组点。线条从平面位置动画到具有不同 y 坐标但始终相同 x 坐标的“模制”形状,类似于折线图动画。

为了使点插值更容易,我在我的 CALayer 子类中添加了一个自定义 CGFloat 属性。我将此属性称为“动画师”(更好的名称可能是进度、插值器等)。我的想法是在该属性上添加一个简单的 CABasicAnimation,从 0.0f 到 1.0f,这样我就可以使用 Core Animation 的计时功能和插值支持,同时仍然能够轻松编写自定义动画。例如,如果一条线的点从 y = 100 变为 y = 130,那么当动画师在 0.0f 时,我在 100,当它的 1.0f 时,我在点 130,中间值给我我的中间点,我继续用这些新点重新画线以获得我的动画。

现在动画效果很好,我禁用了图层操作,添加了 needsDisplayForKey 等,但我的问题是核心动画不准确。 animator 的最终值有时是 0.95 .96 等,而不是 1.0。这很好,因为浮点数存在准确性问题,但是当我的模型值更新(在将动画添加到图层之前设置为 1.0f)时,线条应该重新绘制,我应该得到准确的视觉效果。

这是另一个问题出现的地方。有时动画不会立即删除。大多数时候它会立即被删除,我没有任何问题,但有时它会持续几秒钟,有时甚至几分钟。为了测试我的动画没有被删除的理论,我在我的层中添加了一个简单的 BOOL 标志,当我们在表示层时返回 YES 并且确实有时我看到我的最后一次 drawInContext 调用是在表示层上,动画器值为0.98967f 或其他东西,最后一次 drawInContext 调用动画器 1.0f 和表示层标志为 NO 发生的时间要晚得多。结果,除了明显可怕的用户体验之外,我的视觉跳跃并且不准确。

我已尽力解释我的问题,如果有人想查看代码,我很乐意提供我的测试项目。这里希望一些聪明的人看到这一点并可以帮助我。

编辑 1:已上传整个 Xcode 项目(包括我讨厌的编辑,以显示我尝试过的所有内容)here。

编辑2:有类似问题的人在完成时手动删除动画http://lucas.tiz.ma/blog/2012/04/18/core-animation-is-a-bit-garbage-collection-y/

谢谢。

【问题讨论】:

如果你能向我们展示动画等的代码会更容易提供帮助。 它有很多绘图代码,还要查看控制器代码,这些代码有 5 行等。如果我将它上传到某个地方会更好吗? 已编辑问题并将项目上传到 Dropbox。 我无法重现任何问题。此外,您是否有任何理由不使用 CAShapeLayer 作为路径?您可以在这两种状态之间设置动画。 问题存在并且当你真正测试它时会发生50-100次。密切关注控制台日志以获取准确的动画师值读数。 CAShapeLayer 也不能正确进行复杂的插值,例如有时会导致路径闪烁等。 【参考方案1】:

tl;dr 在 animationDidStop:finished: 委托回调中显式调用 setNeedsDisplay。

根据 Lucas Tizma 的帖子(参见上面的编辑 2),我尝试手动删除动画。我选择了一种比他基于块的方法更简单的方法,方法是将图层设置为设置在它们上的动画的代表。这样,动画开始和停止回调直接到达相关层。好吧,在 animationDidStop:finished: 回调中明确删除动画并不能解决问题。例如,有时(请参阅下面的日志,尤其是时间戳)动画会停止并检查它是否已被删除,这表明它已被删除,但是使用实际模型值的准确绘制发生在很久以后。

// animationDidStop:finished: call back code

NSLog(@"layer animation stopped");

// check if any animations exist
NSLog(@"animation keys: %@", [self animationKeys]);

// remove animations and check
NSLog(@"removing animations");
[self removeAllAnimations];
NSLog(@"animation keys: %@", [self animationKeys]);

// log

2012-10-11 11:47:16.774 ASPathAnimationTest[3017:c07] on presentation layer 1
2012-10-11 11:47:16.774 ASPathAnimationTest[3017:c07] 335 animation draw update, animator is 0.982606
2012-10-11 11:47:16.775 ASPathAnimationTest[3017:c07] startPoint: 100, 90 - endPoint: 100, 100 - newPoint: 100, 99.8261
<snip>
2012-10-11 11:47:16.791 ASPathAnimationTest[3017:c07] startPoint: 1000, 50 - endPoint: 1000, 100 - newPoint: 1000, 99.1303
2012-10-11 11:47:16.792 ASPathAnimationTest[3017:c07] layer animation stopped
2012-10-11 11:47:16.792 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.793 ASPathAnimationTest[3017:c07] removing animations
2012-10-11 11:47:16.793 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.794 ASPathAnimationTest[3017:c07] layer animation stopped
2012-10-11 11:47:16.794 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.794 ASPathAnimationTest[3017:c07] removing animations
2012-10-11 11:47:16.795 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.795 ASPathAnimationTest[3017:c07] layer animation stopped
2012-10-11 11:47:16.819 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.820 ASPathAnimationTest[3017:c07] removing animations
2012-10-11 11:47:16.820 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.821 ASPathAnimationTest[3017:c07] layer animation stopped
2012-10-11 11:47:16.821 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.821 ASPathAnimationTest[3017:c07] removing animations
2012-10-11 11:47:16.822 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.822 ASPathAnimationTest[3017:c07] layer animation stopped
2012-10-11 11:47:16.822 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:47:16.823 ASPathAnimationTest[3017:c07] removing animations
2012-10-11 11:47:16.823 ASPathAnimationTest[3017:c07] animation keys: (null)
2012-10-11 11:48:00.000 ASPathAnimationTest[3017:c07] on presentation layer 0
2012-10-11 11:48:00.000 ASPathAnimationTest[3017:c07] 336 animation draw update, animator is 1.000000
<snip, there are 5 lines so draw and point logs go here>
2012-10-11 11:48:00.021 ASPathAnimationTest[3017:c07] 340 animation draw update, animator is 1.000000
2012-10-11 11:48:00.023 ASPathAnimationTest[3017:c07] startPoint: 100, 90 - endPoint: 100, 100 - newPoint: 100, 100
<snip>
2012-10-11 11:48:00.026 ASPathAnimationTest[3017:c07] startPoint: 1000, 50 - endPoint: 1000, 100 - newPoint: 1000, 100

在查看日志并注意到动画确实被删除的事实后,只是使用实际准确的模型值重新绘制有时直到几秒钟甚至几分钟后才会发生,我更改了 animationDidStop:finished: 委托回调在图层上显式调用 setNeedsDisplay。答对了。

【讨论】:

以上是关于Core Animation (CABasicAnimation) 的不可预测行为的主要内容,如果未能解决你的问题,请参考以下文章

Core Animation 与 GPU

Core Animation 之一

iOS - Core Animation(核心动画)

iOS - Core Animation(核心动画)

带有 Core Graphics 绘图的 Core Animation

Core Animation学习总结