use*_*182 46 iphone core-animation core-graphics calayer ios
我目前正在实施一个CABasicAnimation
动画CALayer
transform
属性.现在,虽然我是Core Animation的新手,但我已经能够收集各种博客和文章,例如objc.io,使用经常(错误的)推荐的方法来获取动画以坚持使用是非常糟糕的主意.fillMode
和removedOnCompletion
动画的属性.这种方法被很多人认为是不好的做法,因为它会在模型层和表示层之间产生差异,因此未来对其中一个层的查询可能与用户看到的不匹配.
相反,推荐的动画制作方法是在将动画添加到动画图层的同时更新模型图层.但是,我很难理解这是如何工作的.我的动画很简单,就像这样:
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
Run Code Online (Sandbox Code Playgroud)
我已经指出了三个尝试使用代码更新模型层的位置
self.layerBeingAnimated.transform = updatedTransform;
Run Code Online (Sandbox Code Playgroud)
在位置1中,图层向右跳转newTransform
并且不动画.在位置2中,图层完全按照我想要的方式从当前变换设置为动画newTransform
.在位置3中,图层向右跳转newTransform
,跳回到旧变换,从fromValue到newTransform正确动画,然后保持在newTransform
.
这是什么交易?更新模型层的正确位置是什么?为什么这三个位置会产生不同的结果?
谢谢!
Dav*_*ist 73
我认为最容易解释三个地点中每个地点的情况,然后是最后的"结论".
我还添加了一些插图,准确显示了你在问题中提到的行为,这样对于那些自己没有尝试过这三件事的人来说会更容易理解.我还扩展了插图,以显示独立层和背衬层(一个附加到视图),我将解释其中有一个区别.
在第一个位置,模型值在创建动画之前更新.完成此操作后,transform属性将保存updatedTransform.这意味着当您从fromValue的图层读取变换时,您将获得updatedValue.这反过来意味着往返于值都是相同的,因此您无法看到动画.
可能使此位置按预期工作的一件事是在分配新值之前读取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];
Run Code Online (Sandbox Code Playgroud)
在第二个示例中,当您读取from值的变换时,该值尚未更新,因此fromValue和toValue不同.之后,模型值将更新为其最终值.这里独立层和背衬层之间实际上存在差异,但我们没有看到它.transform
CALayer上的属性是可动画的,当值发生变化时,它将自动执行"隐式"动画.这意味着动画将添加到"变换"键路径的图层中.但是,当更改发生在动画块之外时,视图会禁用此行为,因此不存在隐式动画.
我们没有看到隐式动画的原因是之后为相同的键路径添加了"显式"动画.这意味着在两种情况下,唯一的显式动画都是可见的,甚至认为在独立图层上运行了两个动画(稍后会详细介绍).如果您感到谨慎,那么您可以禁用独立层的隐式操作(稍后会详细介绍).
这给我们留下了最后的位置.在这种情况下,动画就像上面一样创建,具有不同的fromValue和toValue.唯一的区别是添加显式动画和更改触发隐式动画的属性的顺序.在这种情况下,隐式动画在显式动画之后添加,它们都运行(!).两个动画实际上都是针对位置2运行的,但我们无法看到它,因为之前添加了显式(更长)动画.
由于一切都在快速移动,我放慢了整个图层的速度,试图说明当两个动画同时运行时发生了什么.通过这种方式,可以更容易地看到隐式动画结束时会发生什么.我覆盖了表现良好的背衬层和行为不端的独立层,使它们都是50%透明的.虚线轮廓是原始帧.
对正在发生的事情的简短描述:蓝色视图只获得添加到其中的显式动画(持续时间为1秒).橙色图层首先添加了相同的显式动画,然后添加了隐含的0.25秒动画.显式和隐式动画都不是"加法",意味着它们的toValue和fromValue按原样使用.
免责声明:我不在Apple工作,我没有看过Core Animation的源代码,所以我要说的是根据事情的行为进行猜测.
根据我的理解(参见免责声明),这是每次屏幕刷新产生动画时会发生的情况:对于当前时间戳,图层按照添加的顺序浏览动画并更新演示文稿值.在这种情况下,显式动画设置旋转变换,然后隐式动画到来并设置另一个完全覆盖显式变换的旋转变换.
如果动画配置为"添加",它将添加到演示文稿值而不是覆盖(这是超级强大的).即使使用附加动画,订单仍然很重要.非加法动画可以在以后出现并覆盖整个事物.
由于隐式动画比显式动画短,我们看到对于整个动画的第一部分,值严格来自隐式动画(最后添加).一旦隐式动画结束,唯一剩下的动画就是显式动画,它一直在隐式动画下面运行.因此,当隐式动画结束时,显式动画已经进展了0.25秒,我们看到橙色层跳回到与蓝色视图相同的值,而不是跳回到开头.
在这一点上,问题是,我们如何防止添加两个动画以及我们应该在哪里更新值?更新值的位置不会阻止两个动画(但它可能会影响最终结果的外观).
为了防止将两个操作添加到独立层,我们暂时禁用所有"操作"(动画的更通用术语):
[CATransaction begin];
[CATransaction setDisableActions:YES]; // actions are disabled for now
layer.transform = updatedTransform;
[CATransaction commit]; // until here
Run Code Online (Sandbox Code Playgroud)
当我们这样做时,只有一个动画被添加到图层,因此位置2或3可以工作.这只是一个品味问题.如果您读取oldValue,则还可以使用位置1(只要禁用该操作).
如果您要为后备层设置动画,那么您不必禁用操作(视图会为您执行此操作),但这样做也没有什么坏处.
在这一点上,我可以继续讨论配置动画的其他方法,添加动画是什么,以及为什么在这种情况下需要指定toValue和fromValue.但我认为我已经回答了你提出的问题,而这个答案已经有点偏执了.
归档时间: |
|
查看次数: |
4490 次 |
最近记录: |