14

I'm trying to create a very simple keyframe animation, whereby a graphic Rotates from one angle to another, through a given midpoint.

(The purpose is to be able to animate rotation through an OBTUSE angle of arc GREATER THAN 180 DEGREES, rather than having the animation 'cheat' and go the shortest route, i.e., via the opposite , ACUTE smaller angle -- which can happen when there's only one [i.e, destination] keyframe. To go the 'long' way around, I assume I need an extra keyframe midway through, along the desired arc.)

Here's what I've got so far (which does get the graphic to the desired rotation, via the most acute angle):

#define DEGREES_TO_RADIANS(__ANGLE__) ((__ANGLE__) / 180.0 * M_PI)

...

[UIView beginAnimations:nil context:nil];
CGAffineTransform cgCTM = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(desiredEndingAngle));
[UIView setAnimationDuration:0.5];
graphic.transform = cgCTM;
[UIView commitAnimations];

As I understand it, I’m not looking for animation along a Path (since that’s for Translation, rather than Rotation) ...

Anyway, any help would be VERY much appreciated! Thanks in advance.

  • One quick clarification (as it's been a while since I took Geometry!). The purpose is to Rotate the needle on a SPEEDOMETER-type gauge, whose markings cover MORE THAN 180 DEGREES. As it is now, when the needle goes from near 0 to near Max, it takes the shortest distance to get there ... thus, crossing thru the "6 o'clock" region, where there are no markings (e.g., where it says "MPH" instead). I need a way, essentially, specify which DIRECTION that rotation happens. Presumably, that means Clockwise/Counterclockwise, or thru a specified midpoint. Hence, the idea of an extra keyframe. Thanks! –  Jun 23 '09 at 23:16

3 Answers3

18

Think I’ve got it.

Here’s code which does (in this example) a full 270 DEGREE rotation (1.5*pi radians), including various parameters that can be customized further:

CALayer *layer = rotatingImage.layer;
CAKeyframeAnimation *animation;
animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
animation.duration = 0.5f;
animation.cumulative = YES;
animation.repeatCount = 1;
animation.values = [NSArray arrayWithObjects:       // i.e., Rotation values for the 3 keyframes, in RADIANS
      [NSNumber numberWithFloat:0.0 * M_PI], 
      [NSNumber numberWithFloat:0.75 * M_PI], 
      [NSNumber numberWithFloat:1.5 * M_PI], nil]; 
animation.keyTimes = [NSArray arrayWithObjects:     // Relative timing values for the 3 keyframes
      [NSNumber numberWithFloat:0], 
      [NSNumber numberWithFloat:.5], 
      [NSNumber numberWithFloat:1.0], nil]; 
animation.timingFunctions = [NSArray arrayWithObjects:
      [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn],    // from keyframe 1 to keyframe 2
      [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], nil]; // from keyframe 2 to keyframe 3
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;

[layer addAnimation:animation forKey:nil];

Thanks!

1

Try this:

UIImageView* rotatingImage = [[UIImageView alloc] init]];
[rotatingImage setImage:[UIImage imageNamed:@"someImage.png"]];

CATransform3D rotationTransform = CATransform3DMakeRotation(1.0f * M_PI, 0, 0, 1.0);
CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];

rotationAnimation.toValue = [NSValue valueWithCATransform3D:rotationTransform];
rotationAnimation.duration = 0.25f;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 1;

[rotatingImage.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
Nathan de Vries
  • 15,481
  • 4
  • 49
  • 55
  • Hi, Nathan! Thanks so much for the response and your expertise. I'm getting the following Error on the last line: "request for member 'layer' in something not a structure or union". I imagine I'm missing some other setup (as UIImage doesn't normally have a Layer property). Being brand new to Core Animation, am still a bit stuck. [Also not sure as yet how this specifies a midpoint, or alternatively, a DIRECTION for the rotation (essentially a choice of Clockwise or Counterclockwise), but I'm sure it'll become apparent once I can get this to run.] Many thanks to you/all for any add'l help! –  Jun 23 '09 at 23:03
  • I fixed the code sample -- I was adding the animation to the UIImage instead of a UIImageView containing a UIImage, which won't work for obvious reasons :-) – Nathan de Vries Jun 24 '09 at 01:52
  • Thanks, Nathan, that does make sense & it does compile now. Near as I can tell, though, unfortunately, I seem to be back roughly where I started: Trying to do a rotation of, say, 270 degrees (1.5*pi radians) in one direction ... results in a *90 degree* rotation in the opposite direction instead (i.e., the short way 'round)! I believe the answer is with CAKeyframeAnimation rather than CABasicAnimation, as it gives much more control over the actual movement. I'm playing with that, and will post any answer I come up with, or any further questions under a separate post. Thank you for your time! –  Jun 25 '09 at 00:33
  • This SO question might give you a few practical hints about how to use CAKeyframeAnimation: http://stackoverflow.com/questions/929364/how-to-create-iphones-wobbling-icon-effect – Nathan de Vries Jun 25 '09 at 08:00
1
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, 100, 100);
CGPathAddQuadCurveToPoint(path, NULL, 100, 100, 100, 615);
CGPathAddQuadCurveToPoint(path, NULL, 100, 615, 900, 615);
CGPathAddQuadCurveToPoint(path, NULL, 900, 615, 900, 100);
CGPathAddQuadCurveToPoint(path, NULL, 900, 100, 100, 80);
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
pathAnimation.path = path;
pathAnimation.duration = 10.0;
[someLayer addAnimation:pathAnimation forKey:nil];
Vinoth
  • 119
  • 1
  • 6