这是我的Obj-C编程的第二周,我在动画方面遇到了一些问题。
我使用这个动画:
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 4;
fullRotation.repeatCount= 1000;
[[stick layer] addAnimation:fullRotation forKey:@"60"];}
此动画从我的应用程序启动开始,然后点击一些按钮,这些按钮会在点击时更改动画持续时间,但新动画(代码相同但持续时间不同)从图像的原始位置开始“棒”。我可以做些什么来制作其他动画从当前位置开始360度转弯?感谢。
部分代码以获得更多解释:
-(void)viewDidAppear:(BOOL)animated{
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 4;
fullRotation.repeatCount= 1000;
[[stick layer] addAnimation:fullRotation forKey:@"60"];}
- (IBAction)button1:(UIButton *)sender {
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
fullRotation.duration = 6;
fullRotation.repeatCount= 1000;
[[stick layer] addAnimation:fullRotation forKey:@"60"];}
答案 0 :(得分:19)
有几种不同的方法可以实现您所追求的结果,但在查看这些结果之前,我应该解释问题的根本原因。
动画期间在屏幕上看到的内容不一定与这些图层上的属性值相匹配。实际上,向图层添加动画不会更改图层的动画属性。您在屏幕上看到的动画和值发生在渲染服务器中,该服务器在除应用程序之外的另一个进程中运行。您无法获得这些确切的值,但您可以得到一个近似值,称为 presentation 值。由于我们无法获得渲染服务器的值,因此我们通常只讨论模型值(图层对象上的实际值)和表示值(屏幕上显示的内容(或者至少非常接近)它))。
仅为CABasicAnimation指定toValue
表示它从当前模型值和指定的值设置动画。请注意,文档说它是当前的演示文稿值,但that is actually incorrect。由于模型值永远不会改变,这意味着当添加第二个动画时,它会从未更改的未旋转模型值动画到toValue
。
(作为旁注:由于两个动画使用相同的键,新的动画会替换旧的动画。这并不重要,因为动画不是附加的,所以即使动画不是&#39 ; t替换后,新动画会将其值写在旧动画值上。)
有许多方法可以获得您想要的行为,从最简单的版本开始。
fromValue
如上所述,只有非零toValue
,动画将从当前模型值开始。但是,您可以添加当前演示文稿值的非零fromValue
。
您可以从图层presentationLayer
获取演示文稿价值。从中,您可以使用与动画相同的关键路径和一点KVC(键值编码)来获取当前旋转角度:
NSNumber *currentAngle = [switch.layer.presentationLayer valueForKeyPath:@"transform.rotation"];
如果您只将其设置为动画的fromValue
,您将获得正确的起始值,但旋转可能不再是360度。虽然您可以计算出角度并创建一个新的toValue
,但还有另一个名为byValue
的属性会产生相对变化。指定byValue
和fromValue
(但不是toValue)意味着:
在
fromValue
和(fromValue + byValue)
之间插补。
因此,您可以将动画代码更改为:
CABasicAnimation *fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
fullRotation.fromValue = currentAngle; // the value read from the presentation layer
fullRotation.byValue = @(2.0*M_PI);
fullRotation.duration = 6.0;
此时您的代码应该从正确的值继续,但动画的整体速度可能看起来有点奇怪(即使在此代码更改之前它应该看起来很奇怪)。对于连续旋转的视图,您可能希望它始终以相同的速度旋转(与每次旋转的加速和减速相反)。您可以通过将动画配置为具有线性计时功能来实现此目的:
fullRotation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
这可以为您提供您所追求的行为。一些风格的评论是为重复计数指定INFINITY
或HUGE_VALF
,除非您想要旋转1000次,并在添加图层时使用更具描述性的键(除非您使用的是其他东西的关键(比如从图层中删除动画):
fullRotation.repeatCount = INFINITY;
[stick.layer addAnimation:fullRotation forKey:@"rotate continuously"];
在将其用作生产代码中的解决方案之前,我会三思而行,但它可以作为学习练习而有趣。由于你最常做的是通过将持续时间从4秒更改为6秒来减慢动画速度,因此创建相同效果可以做的一件事就是减慢图层的速度。请注意,这会产生副作用(此图层上的所有动画及其所有子图层也会受到影响)。
一旦将动画添加到图层中,您就无法修改动画,但图层本身也符合CAMediaTiming
协议,这意味着它具有speed
属性。将速度设置为4.0/6.0
并在图层上保留旧动画会降低速度,使每次旋转需要6秒而不是4秒。
再次,有点hacky但有趣的学习练习。