如何在NSImageView内实现NSImage的连续旋转?

9

未来的观众们:

我已经成功完成了这个旋转动画和代码,可以在这个问题中找到相关描述:NSImage rotation in NSView is not working

在继续之前,请为Duncan C的答案点赞。因为我是通过他的答案实现了这个旋转效果。


我有一张像这样的图片:

enter image description here

我想要让这个同步图标不断旋转,在另一个线程上进行。我尝试使用Quartz Composer并将动画添加到QCView中,但它的效果非常疯狂而且速度非常慢。

问题:

如何以非常少的处理开销连续旋转这个图像?

尝试过的方法

我阅读了CoreAnimation、Quartz2D文档,但未能找到使其工作的方法。到目前为止,我唯一知道的是,我必须使用:

  • CALayer
  • CAImageRef
  • AffineTransform
  • NSAnimationContext

现在,我不是期望代码,但一个带有伪代码的理解将是非常好的!

2个回答

15

让一个对象旋转超过180度实际上有点棘手。问题在于您为结束旋转指定了变换矩阵,系统会决定向另一个方向旋转。

我所做的是创建一个小于180度的CABasicAnimation,设置为可添加,并带有重复计数。动画中的每个步骤都使对象更多地进行动画。

以下代码来自iOS应用程序,但在Mac OS中使用的技术是相同的。

  CABasicAnimation* rotate =  [CABasicAnimation animationWithKeyPath: @"transform.rotation.z"];
  rotate.removedOnCompletion = FALSE;
  rotate.fillMode = kCAFillModeForwards;

  //Do a series of 5 quarter turns for a total of a 1.25 turns
  //(2PI is a full turn, so pi/2 is a quarter turn)
  [rotate setToValue: [NSNumber numberWithFloat: -M_PI / 2]];
  rotate.repeatCount = 11;

  rotate.duration = duration/2;
  rotate.beginTime = start;
  rotate.cumulative = TRUE;
  rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

CAAnimation对象作用于层,因此对于Mac OS,您需要在界面构建器中设置“wants layer”属性,然后将动画添加到视图的层中。

要使视图永久旋转,可以将重复计数设置为非常大的数字,例如1e100。

创建动画后,您需要使用以下类似代码将其添加到视图的层中:

[myView.layer addAnimation: rotate forKey: @"rotateAnimation"];

大概就是这些了。


2

更新:

我最近学到了另一种处理大于180度或连续旋转的方法。

有一个特殊的对象叫做CAValueFunction,它可以让您使用任意值(包括指定多个完整旋转的值)对图层的变换应用更改。

您可以创建一个CABasicAnimation来控制图层的变换属性,但是不需要提供变换,而是提供一个NSNumber,表示新的旋转角度。如果您提供一个像20pi这样的新角度,您的图层将会旋转10个完整的旋转(2pi/rotation)。代码如下:

//Create a CABasicAnimation object to manage our rotation.
CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:@"transform"];

rotation.duration = 10.0;
CGFLOAT angle = 20*M_PI;

//Set the ending value of the rotation to the new angle.
rotation.toValue = @(angle);

//Have the rotation use linear timing.
rotation.timingFunction = 
  [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

/*
 This is the magic bit. We add a CAValueFunction that tells the CAAnimation we are 
 modifying the transform's rotation around the Z axis.
 Without this, we would supply a transform as the fromValue and toValue, and 
 for rotations > a half-turn, we could not control the rotation direction.

 By using a value function, we can specify arbitrary rotation amounts and 
 directions and even rotations greater than 360 degrees.
*/

rotation.valueFunction = 
  [CAValueFunction functionWithName: kCAValueFunctionRotateZ];



/*
 Set the layer's transform to it's final state before submitting the animation, so 
 it is in it's final state once the animation completes.
*/
imageViewToAnimate.layer.transform = 
  CATransform3DRotate(imageViewToAnimate.layer.transform, angle, 0, 0, 1.0);

[imageViewToAnimate.layer addAnimation:rotation forKey:@"transform.rotation.z"];

我从一个实际应用中提取了上述代码,并去掉了一些与主题无关的内容。您可以在Github项目KeyframeViewAnimations中看到此代码的使用情况。负责旋转的代码位于名为“handleRotate”的方法中。

3
它围绕着0,0(左下角)旋转会有任何问题吗?这让我疯了,无论我如何调整锚点和图层位置,似乎都无法将它围绕中心旋转。 - robertmiles3
@robertmiles3,我认为这与您尝试动画化的任何对象的锚点有关。使用[myView.layer setAnchorPoint:CGPointMake(0.5, 0.5)] - CoderNinja

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接