Can I use CGAffineTransformMakeRotation to rotate a view more than 360 degrees?

I'm writing an iPhone app, and I've got an image which I'ld like to have swirl outwards.

Currently my code looks like this (wrapped in a beginAnimations/commitAnimations block):

scale = CGAffineTransformScale(CGAffineTransformIdentity, 5.0f, 5.0f);
swirl = CGAffineTransformRotate(scale, M_PI);
[player setTransform:swirl];    
[player setAlpha:0.0f];

But I find that if I try to change the angle of the rotation to, say, 4*M_PI, it doesn't rotate at all. Is it possible to get a 720˚ rotation using CGAffineTransformRotate, or do I have to switch to another technology?

If I have to switch to another technology, would you recommend using another thread (or a timer) to do the animation myself, or would OpenGL be a better route to go?

Thanks, Blake.

Answers


You can rotate a view, by some number of radians, regardless of whether it is less than a full rotation or many multiples of a full rotation, without having to split the rotation into pieces. As an example, the following code will spin a view, once per second, for a specified number of seconds. You can easily modify it to spin a view by a certain number of rotations, or by some number of radians.

- (void) runSpinAnimationWithDuration:(CGFloat) duration;
{
    CABasicAnimation* rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotationAnimation.toValue = [NSNumber numberWithFloat: M_PI * 2.0 /* full rotation*/ * rotations * duration ];
    rotationAnimation.duration = duration;
    rotationAnimation.cumulative = YES;
    rotationAnimation.repeatCount = 1.0; 
    rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

    [myView.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}

You can, but you will need to split your animation into half-circle rotations. I provide an example of this in response to this question, using a repeating CABasicAnimation applied to the layer underneath the view. As I suggest there, doing these half-rotations as parts of a CAKeyframeAnimation would probably be the better way to structure this, because the animation would be smoother (there's a slight hitch in between half-rotations in my example), and you could do a nice acceleration / deceleration at the start and end.


Answer to title: Yes, CGAffineTransform can rotate more than 360 degrees just fine. Answer to question: Yes, but you cannot animate it because there is nothing to animate.

Remember that the affine transformation is a matrix, and that a rotation matrix contains the sine and cosine numbers precomputed. It's as if you said:

CGFloat angle = 4.0 * M_PI;
NSAffineTransformStruct matrix = {
    .m11 = cos(angle),
    .m12 = sin(angle),
    .m21 = -sin(angle),
    .m22 = cos(angle),
    .tx = 0.0,
    .ty = 0.0
};
NSAffineTransform *transform = [NSAffineTransform transform];
[transform setTransformStruct:matrix];

Now, let's review some sample values for cos and sin:

  • cos(0π) = 1
  • sin(0π) = 0
  • cos(2π) = 1
  • sin(2π) = 0
  • cos(4π) = 1
  • sin(4π) = 0

Remember, the matrix doesn't contain the angle -- it only contains the cosine and sine. And those values don't change from one multiple of a circle to another. Therefore, there is nothing to animate.

(Note that Calculator.app gives wrong results for cos(xπ) and sin(xπ). Try Grapher, calc, or Google.)

You will need to split the animation into fractions of a circle. The half-circles Brad Larson suggested will do just fine.


Need Your Help

How to Iterate through all Bundle objects

android bundle sharedpreferences

I am trying to create helper method that would iterate through all Bundle objects, in a generic manner.

java: how can i do dynamic casting of a variable from one type to another?

java casting dynamic-cast

i would like to do dynamic casting for a java variable, the casting type is stored in a different variable.