ios - 更新模型层时 CABasicAnimation 无法正确设置动画

标签 ios iphone core-graphics core-animation calayer

我目前正在实现 CABasicAnimation动画 CALayer transform属性(property)。
现在,虽然我是 Core Animation 的新手,但我已经能够通过各种博客和文章(例如 objc.io)收集到,使用经常(错误地)推荐的方法来使用fillModeremovedOnCompletion动画的属性。这种方法被许多人认为是不好的做法,因为它在模型层和表示层之间产生了差异,因此 future 对这些层之一的查询可能与用户所看到的不匹配。

相反,推荐的动画制作方法是在将动画添加到正在设置动画的图层的同时更新模型图层。但是,我无法准确理解这是如何工作的。我的动画很简单,就像这样:

CATransform3D updatedTransform = [self newTransformWithCurrentTransform];
// Location 1
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
transformAnimation.duration = 1;
transformAnimation.fromValue = [NSValue valueWithCATransform3D:self.layerBeingAnimated.transform]; // Does not work without this.
transformAnimation.toValue = [NSValue valueWithCATransform3D:updatedTransform];
// Location 2
[self.layerBeingAnimated addAnimation:transformAnimation forKey:kTransformAnimationKey];
// Location 3

我已经指出了我尝试使用代码更新模型层的三个位置
self.layerBeingAnimated.transform = updatedTransform;

在位置 1,图层向右跳转到 newTransform并且没有动画。
在位置 2 中,图层完全按照我希望的方式进行动画处理,从当前变换到 newTransform .
在位置 3,图层向右跳转到 newTransform , 跳回到旧的变换,从 fromValue 到 newTransform 正确动画,然后停留在 newTransform .

这里有什么交易?更新模型层的正确位置是什么,为什么这三个位置会产生如此不同的结果?

谢谢!

最佳答案

我认为最容易解释三个位置中的每一个发生了什么,然后在最后给出“结论”。
我还添加了一些插图,准确显示了您在问题中提到的行为,以便那些自己没有尝试过这三件事的人更容易理解。我还扩展了插图以显示一个独立的层和一个支持层(一个附加到 View 的层),我将解释它们之间的区别。
位置 1
在第一个位置,模型值在创建动画之前更新。完成此操作后,transform 属性将保存 updatedTransform。这意味着当您从 fromValue 的图层读取变换时,您会得到 updatedValue。这反过来意味着 to 和 from 值是相同的,所以你看不到动画。
enter image description here
可以使此位置按预期工作的一件事是在分配新值之前读取 oldValue,然后将其用作 fromValue。这将看起来像预期的那样。

// Location 1
CATransform3D oldValue = layer.transform; // read the old value first
layer.transform = updatedTransform;       // then update to the new value
    
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"transform"];
anim.duration  = 1.0;
anim.fromValue = [NSValue valueWithCATransform3D:oldValue];
anim.toValue   = [NSValue valueWithCATransform3D:updatedTransform];
地点 2
在第二个示例中,当您读取 from 值的转换时,该值尚未更新,因此 fromValue 和 toValue 是不同的。之后,模型值更新为其最终值。这里的单机层和背衬层其实是有区别的,只是我们没有看到。 transform CALayer 上的属性是可动画的,并且会在值更改时自动执行“隐式”动画。这意味着动画将添加到“变换”关键路径的图层中。但是,当更改发生在动画块之外时, View 会禁用此行为,因此那里没有隐式动画。
我们之所以没有看到隐式动画,是因为后面为相同的关键路径添加了“显式”动画。这意味着唯一的显式动画将是可见的,在这两种情况下,即使有两个动画在独立层上运行(稍后会详细介绍)。如果您感到谨慎,那么您可以禁用独立层的隐式操作(稍后会详细介绍)。
enter image description here
地点 3
这给我们留下了最后一个位置。在这种情况下,动画就像上面一样创建,不同的 fromValue 和 toValue。唯一的区别是添加显式动画和更改触发隐式动画的属性的顺序。在这种情况下,隐式动画添加在显式动画之后,它们都运行(!)。两个动画实际上都在位置 2 运行,但我们看不到它,因为之前添加了显式(更长)的动画。
enter image description here
由于一切都变得如此之快,我放慢了整个图层的速度,以尝试说明同时运行两个动画时发生的情况。这样就可以更容易地看到隐式动画结束时会发生什么。我已经覆盖了行为良好的背衬层和行为不端的独立层,并使它们都具有 50% 的透明度。虚线轮廓是原始框架。
enter image description here
对正在发生的事情的简短描述:蓝色 View 仅添加了显式动画(持续时间为 1 秒)。橙色层首先添加了相同的显式动画,然后添加了隐式 0.25 秒动画。显式和隐式动画都不是“可加的”,这意味着它们的 toValue 和 fromValue 按原样使用。
免责声明:我不在 Apple 工作,也没有看到 Core Animation 的源代码,所以我要说的是基于事物行为的猜测。
根据我的理解(请参阅免责声明),这是每次屏幕刷新以生成动画时会发生的情况:对于当前时间戳,图层按照动画添加的顺序遍历动画并更新呈现值。在这种情况下,显式动画设置了一个旋转变换,然后隐式动画来设置另一个完全覆盖显式变换的旋转变换。
如果动画被配置为“可加的”,它将添加到呈现值而不是覆盖(这是 super 强大的)。即使使用附加动画,顺序仍然很重要。非附加动画可能会在稍后出现并覆盖整个内容。
由于隐式动画比显式动画短,我们看到对于整个动画的第一部分,值严格来自隐式动画(最后添加)。一旦隐式动画完成,唯一剩下的动画就是一直在隐式动画下面运行的显式动画。所以当隐式动画结束时,显式动画已经进行了 0.25 秒,我们看到橙色层跳回到与蓝色 View 相同的值,而不是跳回到开头。
我们应该在哪里更新值?
此时,问题来了,如何防止两个动画被添加,应该在哪里更新值呢?值更新的位置不会阻止出现两个动画(但它会影响最终结果的外观)。
为了防止两个 Action 被添加到独立层,我们暂时禁用所有“ Action ”(动画的更通用术语):
[CATransaction begin];
[CATransaction setDisableActions:YES]; // actions are disabled for now
layer.transform = updatedTransform;
[CATransaction commit];                // until here
当我们这样做时,只有一个动画被添加到图层中,所以位置 2 或 3 都可以工作。这只是品味问题。如果您读取 oldValue,您还可以使用位置 1(只要该操作被禁用)。
如果您正在为支持层设置动画,那么您不必禁用操作( View 会为您执行此操作),但这样做也无妨。

在这一点上,我可以继续讨论配置动画的其他方法,什么是附加动画,以及为什么在这种情况下需要同时指定 toValue 和 fromValue。但我认为我已经回答了你提出的问题,这个答案已经有点长了。

关于ios - 更新模型层时 CABasicAnimation 无法正确设置动画,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23939398/

相关文章:

iphone - Mac OS X 和/或 iOS 中的三元光栅操作?

ios - 在后台线程上使用CoreGraphics调整图像大小时发生内存泄漏

iOS 8 以一种奇怪的方式崩溃

ios - Never Get RENEWAL Notification Type on Apple status 更新通知

ios - 使用 Swift 从特定网页检索和解析文本

ios - 使用自动调整大小的阿拉伯语英语 iPhone 用户界面?

iphone - 操作系统状态错误 1718449215

ios - CGRect 调用中的 Swift 额外参数 "width"

iphone - 利用本周和周末在 2 个 NSDate 之间签到

swift - 从灰度矩阵创建 CGImage/UIImage