This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Can I use CGAffineTransformMakeRotation to rotate a view more than 360 degrees?
I'm trying to create a game where pushing a button spins an dial image, having trouble with the rotation code. Goal is to spin the image from its current position by a % of 360, i.e .4 * 360, spin the image 144 degrees. Thanks Guys!
-(IBAction)spin:(id)sender
{
float strenght = DEGREES_TO_RADIANS(.5 * 360);
[UIView animateWithDuration:0.5f delay:0.0f options:UIViewAnimationCurveEaseOut animations:^
{
[spinner_iv setTransform:CGAffineTransformRotate([spinner_iv transform],strenght)];
}
completion:^(BOOL finished)
{
//done
}];
}
UIView animations using CGAffineTransform take the 'shortest path', so if you request a clockwise rotation of 270 degrees, it will animate anticlockwise by 90 degrees.
You can get any number of spins if you instead rotate the view layer using CATransform3D - yes, use this even if you are rotating in 2D. See Can I use CGAffineTransformMakeRotation to rotate a view more than 360 degrees?
Converting degrees to radians is
Radians = Degrees * (PI/180)
Related
I have a sublclass of a CCSprite that rotates throughout the game and there is a shield that has to rotate around the sprite according to the sprite's rotation. So if the sprite's rotation is 75 degrees there should be a CGRect located at 75 degrees. The dimensions of the CGRect are subordinate as it almost resembles a square.
What I did is:
I subclassed CCSprite and added a property called shieldArea.
Upon initialization I set this rect to be
self.shieldArea = CGRectMake(self.position.x-30, self.position.y, 8, 10);
Then I rotate the sprite itself, however, the rect stays at its initial position.
I hoped that the CGrect would be affected by the rotation, but I kind of expected it not to affect it, of course, why should it ? So, my question is, how do I rotate a CGRect at all ? Or do I have to add a new CGRect all the time ?
Side notes: I do not want to use Box2d or anything the like. I handle collision detection myself.
Have you tried CGAffineTransform?
Something like this:
float centerX = myOldRect.origin.x + (myOldRect.size.width / 2.0);
float centerY = myOldRect.origin.y + (myOldRect.size.height / 2.0);
CGAffineTransform rotation = CGAffineTransformMakeRotation(someAngleInRadians);
CGAffineTransform moveAnchor = CGAffineTransformMakeTranslation(centerX, centerY);
CGAffineTransform centeredRotation = CGAffineTransformConcat(moveAnchor, rotation);
CGRect rotatedRect = CGRectApplyAffineTransform(myOldRect, centeredRotation);
Note, this is NOT tested. Use at your own risk :p
I have a custom UIImageView, I can drag it around screen by making a translation with (xDif and yDif is the amount fingers moved):
CGAffineTransform translate = CGAffineTransformMakeTranslation(xDif, yDif);
[self setTransform: CGAffineTransformConcat([self transform], translate)];
Let's say I moved the ImageView for 50px in both x and y directions. I then try to rotate the ImageView (via gesture recognizer) with:
CGAffineTransform transform = CGAffineTransformMakeRotation([recognizer rotation]);
myImageView.transform = transform;
What happens is the ImageView suddenly moves to where the ImageView was originally located (before the translation - not from the moved position + 50px in both directions).
(It seems that no matter how I translate the view, the self.center of the ImageView subclass stays the same - where it was originally laid in IB).
Another problem is, if I rotate the ImageView by 30 deg, and then try to rotate it a bit more, it will again start from the original position (angle = 0) and go from there, why wouldn't it start from the angle 30 deg and not 0.
You are overwriting the earlier transform. To add to the current transform, you should do this –
myImageView.transform = CGAffineTransformRotate(myImageView.transform, recognizer.rotation);
Since you're changing the transform property in a serial order, you should use CGAffineTransformRotate, CGAffineTransformTranslate and CGAffineTransformScale instead so that you add to the original transform and not create a new one.
I want to rotate a + to become an x, but it's not rotating via the center of the +. How can i get it to rotate via that point?
As you suggest just rotate the label :)
CGAffineTransform rotare = CGAffineTransformMakeRotation(45*M_PI/180.0f);
[plusLabel setTransform:rotare];
If the label is not rotating around the + center include the QuartzCore and rotate the [plusLabel layer]
CATransform3D rotate3D = CATransform3DMakeRotation(45*M_PI/180.0f, 0, 0, 1);
[[plusLabel layer] setAnchorPoint:CGPointMake(0.4, 0.6)]; // The center of Plus in my case
[[plusLabel layer] setTransform:rotate3D];
I am writing an iPhone programer, and
I want to make a button with is rotate 180 degree, I try to use the multi-touch track pad to rotate a UIbutton, but it don't success, how can I do it? or I need to do it by code?
You can't do it from Interface Builder. You have to rotate it from your code, using the transform property of your UIButton, which is a CGAffineTransform struct.
You can use the CGAffineTransformMakeRotation() to set it.
myButton.transform = CGAffineTransformMakeRotation( ( 180 * M_PI ) / 180 );
The first 180 in the code is the angle in degrees. The operation converts it to radians.
I was wanting to do this same thing - rotate a button 180 degrees when tapped - but do it using an animation. Neurofluxation's answer does the 180 degree rotation with an animation, but it isn't permanent. Macmade's answer does the 180 degree rotation, but doesn't do it with an animation. So if you're like me and would like to do a 180 degree rotation with animation use this code:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.35];
// (180 * M_PI) / 180 == M_PI, so just use M_PI
myButton.transform = CGAffineTransformMakeRotation(M_PI);
[UIView commitAnimations];
As well, if you want to rotate back to the starting position (ie 0 degree rotation) then put the following in between the animation code like above:
myButton.transform = CGAffineTransformMakeRotation(0);
As to a use case for such a button, Evernote's show/hide keyboard button does a really slick 180 degree rotation which can be recreated using the above code.
Well, here we go:
CABasicAnimation *halfTurn;
halfTurn = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
halfTurn.fromValue = [NSNumber numberWithFloat:0];
halfTurn.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
halfTurn.duration = 0.5;
halfTurn.repeatCount = 1;
[myButton addAnimation:halfTurn forKey:#"180"];
Hope that helps... Im typing from my PC though, not my Mac - So I hope that's right!
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!
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
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
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];
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.