8
votes

Sorry if this is obvious or covered elsewhere, but i've been googling all day and haven't found a solution that actually worked.

My problem is as follows: I am currently drawing an image in a full screen UIView, for examples sake we'll say the image is in the bottom right corner of the UIView. I'd like to do a rotation transform(CGAffineTransformMakeRotation) at the center of that image, however, by default the rotation command rotates around the center of the UIView it self. As a result, my image moves around the screen when i rotate instead of it staying in place and rotating around its own center.

From what i've gathered, i need to translate my context so that the origin(center of the UIView) is at the center of my image, Rotate, and then restore the context by translating back to the original spot.

The following is the closest thing i've gotten to work, but the problem is that while the image is rotating, it moves downward while it's rotating. I think this is caused by animation tweening the 1st step translate and 3rd step translate instead of just realizing that the beginning and end point on the translates would be the same...

// Before this i'd make a call to a function that draws a path to a passed in context
CGAffineTransform inverseTranslation = CGAffineTransformMakeTranslation( transX, transY );
CGAffineTransform translation = CGAffineTransformMakeTranslation( -transX, -transY );
CGAffineTransform rot = CGAffineTransformMakeRotation( 3.14 );
CGAffineTransform final = CGAffineTransformConcat( CGAffineTransformConcat( inverseTranslation, rot ), translation );
// Then i apply the transformation animation like normal using self.transform = final etc etc

I've also tried stuff like CGContextTranslateCTM and CGContextSaveGState/UIGraphicsPushContext, but these seem to have little effect.

I've been fighting with this for days and my current solution seems close, but i have no clue how to get rid of that translating tweening. Does anyone have a solution for this or a better way to go about this?

[update] For the time being i'm drawing my image centered at the UIview's center and then setting the UIView.center property to the origin i'd like to rotate and then doing the rotate command. Seems like a bit of a hack, but until i can get the real translates working it's my only choice. Thanks!

4

4 Answers

14
votes

duncanwilcox' answer is the right one, but he left out the part where you change the anchor of the view's layer to the point you want to rotate around.

CGSize sz = theview.bounds.size;
// Anchorpoint coords are between 0.0 and 1.0
theview.layer.anchorPoint = CGPointMake(rotPoint.x/sz.width, rotPoint.y/sz.height);
[UIView beginAnimations:@"rotate" context:nil];
theview.transform = CGAffineTransformMakeRotation( 45. / 180. * M_PI );
[UIView commitAnimations];

This is documented here: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/Layers.html

7
votes

This is also an option: a simple change of basis ;-)

CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, angle);
transform = CGAffineTransformTranslate(transform,-x,-y);

where (x,y) is the rotation center you like

2
votes

Rotation happens around the anchorPoint of the view's layer. The default for the anchorPoint is the center (0.5, 0.5), so the rotation alone without the translations should suffice.

Did a quick test and this works for me:

[UIView beginAnimations:@"rotate" context:nil];
self.transform = CGAffineTransformMakeRotation( 45. / 180. * 3.14 );
[UIView commitAnimations];
1
votes

If you don't want an animation to occur, but just set the new rotation, you can use this:

CGFloat newRotation = 3.14f 

[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.0]; // no tweening
CGAffineTransform transform = CGAffineTransformMakeRotation(newRotation);
self.transform = transform;
[UIView commitAnimations];

The rotation should indeed take place around the center of the UIView. Setting the animationDuration to zero garantees no tweening should happen.

Be sure though you don't do this 60 times a second. It's very tempting to create game like animations with these tools. These kind of animations aren't exactly meant for a frame to frame based, "lots of sprites flying everywhere" game.

For that - and I've been down that road - the only way to go, is OpenGL.