ios 使用 CABasicAnimation 多次旋转 UIImageView

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17426802/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:11:24  来源:igfitidea点击:

Using CABasicAnimation to rotate a UIImageView more than once

ioscore-animation

提问by BytesGuy

I am using a CABasicAnimation to rotate a UIImageView90 degrees clockwise, but I need to have it rotate a further 90 degrees later on from its position after the initial 90 degree rotation.

我正在使用 CABasicAnimationUIImageView顺时针旋转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"];

Using the code above works initially, the image stays at a 90 degree angle. If I call this again to make it rotate a further 90 degrees the animation starts by jumping back to 0 and rotating 90 degrees, not 90 to 180 degrees.

使用上面的代码最初有效,图像保持在 90 度角。如果我再次调用它使其进一步旋转 90 度,动画开始时会跳回 0 并旋转 90 度,而不是 90 到 180 度。

I was under the impression that animation.additive = YES;would cause further animations to use the current state as a starting point.

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

Any ideas?

有任何想法吗?

采纳答案by Iducool

pass incremental value of angle see my code

传递角度的增量值,请参阅我的代码

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;
  }
}

Above code is just for idea. Its not tested

以上代码仅供参考。它没有经过测试

回答by David R?nnqvist

tl;dr:It is very easy to misuse removeOnCompletion = NOand most people don't realize the consequences of doing so. The proper solution is to change the model value "for real".

tl;dr:它很容易被误用,removeOnCompletion = NO而且大多数人没有意识到这样做的后果。正确的解决方案是“真实地”更改模型值。



First of all: I'm not trying to judge or be mean to you. I see the same misunderstanding over and over and I can see why it happens. By explaining whythings happen I hope that everyone who experience the same issues and sees this answer learn more about what their code is doing.

首先:我不是要评判你或对你刻薄。我一遍又一遍地看到同样的误解,我明白它为什么会发生。通过解释事情发生的原因,我希望遇到相同问题并看到此答案的每个人都能更多地了解他们的代码在做什么。

What went wrong

什么地方出了错

I was under the impression that animation.additive = YES;would cause further animations to use the current state as a starting point.

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

That is very true and it's exactly what happens. Computers are funny in that sense. They always to exactly what you tellthem and not what you wantthem to do.

这是非常正确的,而且正是发生的事情。从这个意义上说,计算机很有趣。他们总是完全按照你告诉他们的,而不是你想让他们做什么。

removeOnCompletion = NOcan be a bitch

removeOnCompletion = NO可以是个婊子

In your case the villain is this line of code:

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

animation.removedOnCompletion = NO;

It is often misused to keep the final value of the animation after the animation completes. The only problem is that it happens by not removing the animation from the view. Animations in Core Animation doesn't alter the underlying property that they are animating, they just animate it on screen. If you look at the actual value during the animation you will never see it change. Instead the animation works on what is called the presentation layer.

它经常被误用于在动画完成后保留动画的最终值。唯一的问题是它是通过不从视图中删除动画而发生的。Core Animation 中的动画不会改变它们动画的底层属性,它们只是在屏幕上动画。如果您在动画期间查看实际值,您将永远不会看到它发生变化。相反,动画在所谓的表示层上工作。

Normally when the animation completes it is removed from the layer and the presentation layer goes away and the model layer appears on screen again. However, when you keep the animation attached to the layer everything looks as it should on screen but you have introduced a difference between what the property says is the transform and how the layer appears to be rotated on screen.

通常,当动画完成时,它会从图层中移除,表示层消失,模型层再次出现在屏幕上。但是,当您将动画附加到图层时,所有内容在屏幕上看起来都应该如此,但是您引入了属性所说的变换与图层在屏幕上旋转的方式之间的差异。

When you configure the animation to be additive that means that the from and to values are addedto the existing value, just as you said. The problem is that the value of that property is 0. You never change it, you just animate it. The next time you try and add that animation to the same layer the value still won't be changed but the animation is doing exactly what it was configured to do: "animate additively from the current value of the model".

当您将动画配置为可加性时,这意味着 from 和 to 值将添加到现有值中,正如您所说。问题在于该属性的值为 0。您永远不会更改它,您只是对其进行动画处理。下次您尝试将该动画添加到同一层时,该值仍然不会更改,但动画正在执行其配置的功能:“从模型的当前值添加动画”。

The solution

解决方案

Skip that line of code. The result is however that the rotation doesn't stick. The better way to make it stick is to change the model. Set the new end value of the rotation before animating the rotation so that the model looks as it should when the animation gets removed.

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

byValueis like magic

byValue就像魔法

There is a very handy property (that I'm going to use) on CABasicAnimationthat is called byValuethat can be used to make relative animations. It can be combined with either toValueand fromValueto do many different kinds of animations. The different combinations are all specified in its documentation (under the section). The combination I'm going to use is:

有一个非常方便的属性(我将要使用)CABasicAnimation被调用byValue,可用于制作相关动画。它可与组合toValue,并fromValue做许多不同种类的动画。不同的组合都在其文档中指定(在 部分下)。我要使用的组合是:

byValueand toValueare non-nil. Interpolates between (toValue - byValue)and toValue.

byValue并且toValue是非nil。在(toValue - byValue)和之间进行插值toValue

Some actual code

一些实际代码

With an explicit toValueof 0 the animation happens from "currentValue-byValue" to "current value". By changing the model first current value is the end value.

显式toValue为 0 时,动画从“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"];

Small disclaimer:

小免责声明

I didn't run this code but am fairly certain that it runs as it should and that I didn't do any typos. Correct me if I did. The entire discussion is still valid.

我没有运行这段代码,但我很确定它按预期运行,而且我没有做任何错别字。如果我这样做了,请纠正我。整个讨论仍然有效。