How to rotate a UIbutton in Xcode + IB? - iphone

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!

Related

CGAffineRotation Skews Image Photos

My iOS has registered for device orientation change notifications via NSNotificationCenter, and has a method that responds to the different orientation changes. The following code is called to change the orientation and location of a view when rotating the phone to "landscape-left".
camAngle = [(NSNumber *)[_cameraToggleButton valueForKeyPath:#"layer.transform.rotation.z"] floatValue];
camDegrees = (RADIANS_TO_DEGREES(camAngle));
if (!(camDegrees == 90)) {
_cameraToggleButton.alpha = 0.0;
_cameraToggleButton.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(90));
_cameraToggleButton.frame = CGRectMake(274, 350, 66, 54);
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.4];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
_cameraToggleButton.alpha = 1.0;
[UIView commitAnimations];
}
And my equations to convert radians and degrees:
#define RADIANS_TO_DEGREES(radians) ((radians) * (180.0 / M_PI))
#define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
The view rotates correctly and assumes the correct position on screen, but the sides of the image are suddenly squashed, making the image look condensed. This only happens when rotating the phone into landscape position (left or right). Rotating to upside down or back to portrait translates and rotates the view fine, with essentially the same code. What could cause this skewing of the images in landscape position?
You should not set the frame of the _cameraToggleButton after you set the rotation transform on it. To re-position the _cameraToggleButton after you set the rotation, you should change it's center like so:
_cameraToggleButton.center = CGPointMake(274, 350);
Also, as someone else suggested, use UIViewContentModeScaleAspectFit instead of UIViewContentModeScaleToFill.

Spinning Wheel Game: Trouble with rotation image [duplicate]

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)

smooth animation in iOS using CoreAnimation

CoreAnimation is a pretty easy thing, but:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:30];
MyImageView.frame = CGRectOffset(MyImageView.frame, 100, 0);
[UIView commitAnimations];
I want to move the ImageView by 100 Pixel veeeery slowly. Therefore all positioning values are double I expect the Layoutsystem to position the items with subpixel accuracy.
Butt when I watch this animation i see the ImageView "jumping" pixelwise instead of a smooth traveling.
Any ideas to come to a real subpixelpositioning?
I also tried to set the position with a timer and recalculate the frame-values, but same effect.
Update:
In an other part of my App I use the Accelerometer to update the position of a ImageView, and do basicly calculate the position ad size of the graphic an then do:
MyImageView.frame = newCGRect;
I get around 60 Updates/s from the Accelerometer and added the LowPass-Filter from the Accelerometer example from Apple.
Here the positioning is perfect?!?!
Why does this do not happen with CoreAnimation?
Thanks for any help.
Try using CGAffineTransformTranslate(MyImageView.transform, 100, 0) instead of CGRectOffset.
Reference here:
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGAffineTransform/Reference/reference.html
If you use CABasicAnimation in QuartzCore framework, you can smoothen your animation using "CAMediaTimingFunction". Built-in alternatives worked for me but as far as I know you can define your own timing functions as well.
CABasicAnimation *starShineAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
starShineAnimation.removedOnCompletion = NO;
starShineAnimation.fillMode = kCAFillModeForwards;
starShineAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
....

how can I use animation in cocos2d?

I am trying to develop a Roulette game for iPhone. How can I animation (spin) the Roulette board?
It's quite simple in Cocos2D:
[sprite runAction:[RotateBy actionWithDuration:dur angle:360]];
to make one turn or
id action = [RepeatForever actionWithAction: [RotateBy actionWithDuration:dur angle:360]];
[sprite runAction:action];
and
[sprite stopAction:action];
if you need to rotate continuously.
Don't forget to make sure that sprite transformAnchor is set to center of the image. And I guess next question should arise - how to make it stop smoothly ;)
More on actions: http://lethain.com/entry/2008/oct/03/notes-on-cocos2d-iphone-development (it's for older version, so it uses deprecated 'do' instead of 'runAction')
I have no idea how to do this in cocos2d (or even what that is), but you can do this using Core Animation either with CALayers or UIViews. Probably the simplest way would be to create a UIImageView containing an image of your roulette wheel and animate that.
To accomplish this, first set up your UIImageView by initializing it with your roulette wheel image. When you want the wheel to spin, use the following code:
CATransform3D rotationTransform = CATransform3DMakeRotation(1.0f * M_PI, 0, 0, 1.0);
CABasicAnimation* rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform"];
rotationAnimation.toValue = [NSValue valueWithCATransform3D:rotationTransform];
rotationAnimation.duration = 0.25f;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = 10;
[rotatingImage.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
assuming that rotatingImage is your UIImageView.
In this example, the wheel would rotate 5 times, with each rotation taking 0.5 seconds. The rotations are split in half because Core Animation will go to the next closest state, so the most you can rotate something is a half rotation before the animation wants to rotate in the other direction. That is, the pi radian (180 degree) rotation here goes a half-circle, but if you used (1.5f * pi) for your rotation angle, it would only go a quarter-circle. Likewise, if you used (0.999f * pi), the circle would rotate in a clockwise manner.
You'll want to implement acceleration and deceleration of your wheel, and for those a CAKeyframeAnimation would take the place of the CABasicAnimation in this example.
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"];
}
There are a couple of ways you can do it.
If you have the frame-by-frame animation for the wheel, check out AtlasDemo (part of cocos2d distribution).
Otherwise, take a look at Sprite's RotateBy: method.

Can i move the origin when doing a rotation transform in Quartz 2D for the iPhone?

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.