CABasicAnimation从当前图层位置开始

时间:2014-08-05 14:17:05

标签: ios objective-c layer cabasicanimation

这是我的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"];}

1 个答案:

答案 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的属性会产生相对变化。指定byValuefromValue(但不是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];

这可以为您提供您所追求的行为。一些风格的评论是为重复计数指定INFINITYHUGE_VALF,除非您想要旋转1000次,并在添加图层时使用更具描述性的键(除非您使用的是其他东西的关键(比如从图层中删除动画):

fullRotation.repeatCount    = INFINITY;
[stick.layer addAnimation:fullRotation forKey:@"rotate continuously"];

改变图层的速度

在将其用作生产代码中的解决方案之前,我会三思而行,但它可以作为学习练习而有趣。由于你最常做的是通过将持续时间从4秒更改为6秒来减慢动画速度,因此创建相同效果可以做的一件事就是减慢图层的速度。请注意,这会产生副作用(此图层上的所有动画及其所有子图层也会受到影响)。

一旦将动画添加到图层中,您就无法修改动画,但图层本身也符合CAMediaTiming协议,这意味着它具有speed属性。将速度设置为4.0/6.0并在图层上保留旧动画会降低速度,使每次旋转需要6秒而不是4秒。

再次,有点hacky但有趣的学习练习。

相关问题