使用CABasicAnimation旋转UIImageView不止一次

我正在使用CABasicAnimation将UIImageView顺时针旋转90度,但是我需要在初始90度旋转之后将它旋转90度。

 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; animation.duration = 10; animation.additive = YES; animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards; animation.fromValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(0)]; animation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(90)]; [_myview.layer addAnimation:animation forKey:@"90rotation"]; 

使用上面的代码最初工作,图像停留在90度的angular度。 如果我再次调用它使其进一步旋转90度,则animation首先跳回到0并旋转90度,而不是90度旋转180度。

我的印象是animation.additive = YES; 会导致进一步的animation使用当前状态作为起点。

有任何想法吗?

通过增量值的angular度看我的代码

 static int imgAngle=0; - (void)doAnimation { CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; animation.duration = 5; animation.additive = YES; animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards; animation.fromValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(imgAngle)]; animation.toValue = [NSNumber numberWithFloat:DEGREES_TO_RADIANS(imgAngle+90)]; [self.imgView.layer addAnimation:animation forKey:@"90rotation"]; imgAngle+=90; if (imgAngle>360) { imgAngle = 0; } } 

上面的代码只是想法。 它没有testing

tl; dr:误用removeOnCompletion = NO很容易,大多数人都没有意识到这样做的后果。 正确的解决scheme是改变模型值“真实”。


首先:我不是要判断你的意思, 我一遍又一遍地看到同样的误解,我可以看出为什么会发生。 通过解释为什么会发生这样的事情,我希望每个遇到同样问题并且看到这个答案的人都能更多地了解他们的代码在做什么。

什么地方出了错

我的印象是animation.additive = YES; 会导致进一步的animation使用当前状态作为起点。

这是非常真实的,这正是发生的事情。 电脑在这个意义上是有趣的。 他们总是完全按照你告诉他们的,而不是你想要他们做的。

removeOnCompletion = NO可以是一个婊子

在你的情况下,恶棍是这样的代码行:

 animation.removedOnCompletion = NO; 

animation完成后,经常会误用animation的最终值。 唯一的问题是,它不会从视图中删除animation。 核心animation中的animation不会改变他们animation的基础属性,他们只是在屏幕上animation。 如果您在animation期间查看实际值,您将永远不会看到它的变化。 相反,animation在所谓的表示层上工作。

通常当animation完成时,它将从图层中移除,并且表示层消失,模型层将再次出现在屏幕上。 但是,当您将animation附加到图层上时,所有内容都应该在屏幕上显示,但是您已经介绍了属性所表示的图层转换以及图层在屏幕上的旋转方式。

当您将animationconfiguration为叠加时,就像您所说的那样,意味着from和to的值被添加到现有的值。 问题是,该属性的值是0.你永远不会改变它,你只是animation。 下一次尝试将该animation添加到同一图层时,该值仍然不会更改,但animation完全按照其configuration执行的操作:“从模型的当前值附加地animation”。

解决scheme

跳过那行代码。 然而结果是旋转不坚持。 让它坚持下去的更好方法是改变模型。 在animation旋转之前设置旋转的新的最终值,以便在animation被移除时模型看起来应该如此。

byValue就像魔术一样

CABasicAnimation中有一个非常方便的属性(我将使用),它被称为byValue ,可以用来制作相对animation。 它可以结合fromValuefromValue来做很多不同types的animation。 所有不同的组合都在其文档(在该章节下)中指定。 我将要使用的组合是:

byValuebyValuenil(toValue - byValue)和值之间的插值。

一些实际的代码

显式toValue为0时,animation从“currentValue-byValue”变为“当前值”。 通过改变模型首先当前值是最终值。

 NSString *zRotationKeyPath = @"transform.rotation.z"; // The killer of typos // Change the model to the new "end value" (key path can work like this but properties don't) CGFloat currentAngle = [[_myview.layer valueForKeyPath:zRotationKeyPath] floatValue]; CGFloat angleToAdd = M_PI_2; // 90 deg = pi/2 [_myview.layer setValue:@(currentAngle+angleToAdd) forKeyPath:zRotationKeyPath]; CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:zRotationKeyPath]; animation.duration = 10; // @( ) is fancy NSNumber literal syntax ... animation.toValue = @(0.0); // model value was already changed. End at that value animation.byValue = @(angleToAdd); // start from - this value (it's toValue - byValue (see above)) // Add the animation. Once it completed it will be removed and you will see the value // of the model layer which happens to be the same value as the animation stopped at. [_myview.layer addAnimation:animation forKey:@"90rotation"]; 

小免责声明

我没有运行这个代码,但相当肯定它运行,因为它应该和我没有做任何错别字。 纠正我,如果我做到了。 整个讨论仍然有效。