I'm trying to 3D animate an UIImageView on X axis so it will do a 180 degrees rotation. At 90 degres I want to change the image. (that is why i "broke" the animation in 2).
Animation works well, but the problem is that the second image is drawn upside down. Any ideas what should i do for the image to be drawn normal?
Here is my code
i++;
[UIView animateWithDuration:2 animations:^{
self.imageView.layer.transform = CATransform3DMakeRotation(-M_PI/2 , 1, 0,0);
} completion:^(BOOL finished){
UIImage *bottomI = (UIImage *)[bottom objectAtIndex:i];
self.second.image =bottomI;
[UIView animateWithDuration:2 animations:^{
imageView.layer.transform = CATransform3DMakeRotation(M_PI , 1, 0,0);
} completion:^(BOOL finised){
}];
}];
What I've done (using grouped CABasicAnimation objects instead of view animations, but the same trick should work) is to rotate the view/layer the first 90 degrees, then rotate it 180 degrees without animation before starting the second half of the animation. That way, the second half of the animation actually causes the front face of the view/layer to rotate into view as if it was the back face, but not backwards.
The view/layer is edge-on to the viewer while you are switching it's image and rotating it 180 degrees, so the user can't see those changes. When it rotates the remaining 90 degrees, the new image is in place and it appears to be revealing the back side of the view/layer.
It works perfectly.
When you are 3d rotating a view, it is similar to rotating an object in real life. So, once the rotation is more than 90 degrees, it would invert the object. Which is why your second image is inverted. The simplest thing to do is to set the affine transform of the image to rotate it by 180 degrees before adding it in.
EDIT: My silliness....
What I intended was this
bottomI.orientation = UIImageOrientationDown
Related
I have the following super simple animation, I'm basically rotating a view 2 radians from its original angle/center, it rotates fine my only misunderstanding is why does the view move from its original position when the rotation occurs.
[UIView animateWithDuration:1.0 animations:^{
self.someView.transform = CGAffineTransformMakeRotation( 2 );
}];
Why does the view moves when rotated with the code above?
I'm currently trying to discern the information in the CGAffineTransform Reference.
Understanding the anchor point.
I found this threads but it doesn't show a concrete answer.
Why rotating imageView, it changes position?
Thanks a lot
You need to set the anchor point of your view to rotate around.
self.somview.layer.anchorPoint = CGPointMake(0.5, 0.5);
Then start the rotation.
From Apple documentations
#property(nonatomic) CGAffineTransform transform Changes to this
property can be animated. Use the beginAnimations:context: class
method to begin and the commitAnimations class method to end an
animation block. The default is whatever the center value is (or
anchor point if changed)
Link: https://developer.apple.com/library/ios/documentation/GraphicsImaging/Reference/CALayer_class/Introduction/Introduction.html#//apple_ref/occ/instp/CALayer/anchorPoint
image from here http://www.raywenderlich.com/9864/how-to-create-a-rotating-wheel-control-with-uikit
- As you see the anchor point is the point with the value from 0.0 - 1.0 for X and Y
when you rotate the rotation will be around these points
NOTE: you need to import QuartzCore
I am adding another answer due to #fs_tigre request. The problem is with the auto layouts in your xib file, unfortunately is it unknown why that affects the transform.
Now here is the steps I did to solve the issue:
1- first you need to get rid off your auto layout (yes, you have to)
uncheck Use Autolayout
2- remove all constraints and autoresizing masks for your view that will be rotated, as in the screenshot
(Here I have my blue box, see on the right autoresizing, nothing is selected)
I have made some changes for your rotation's code
self.someView.layer.anchorPoint = CGPointMake(0.5, 0.5);
// one degree = pi/180. so...
// rotate by 90
CGFloat radians = (M_PI/180) * 90;
[UIView animateWithDuration:1.0 animations:^{
self.someView.transform = CGAffineTransformRotate(self.someView.transform, radians);
}];
Click rotate and see the magic :)
The "anchor" of CGAffineTransformMakeRotation is the X,Y of the view. You can try this:
CGPoint center = self.someView.center;
[UIView animateWithDuration:1.0 animations:^{
self.someView.transform = CGAffineTransformMakeRotation( 2 );
self.someView.center = center;
}];
So I'm trying to perform a (seemingly) simple transform animation on a UIImageView by just moving it up 100 points. This is my code:
[UIView animateWithDuration:1 delay:1 options:nil animations:^(void) {
CGAffineTransform tf = CGAffineTransformMakeTranslation(0, -100);
[image setTransform:tf];
} completion:^(BOOL finished) {} ];
It works...but it for some reason chooses a new origin for my UIImageView to start from. For example, if the image's original center coordinates are (300, 400), then by my code it should translate up 100 points to (300, 300). But for some reason, the code makes the image start a little bit lower than where it should, like around (300, 450), and then it'll move up 100 to (300, 350). How can I get it to do the animation from where the image is originally?
If you prefer to use transformation for this procedure, then you should try to get original transform and translate it by 100 px.
[image setTransform:CGAffineTransformTranslate(image.transform, 0, -100)];
If your goal is to translate the subview relative to its superview's coordinate system, you'll have more predictable results simply animating the center property:
[UIView animateWithDuration: 1.0 animations:^{
image.center = CGPointMake(image.center.x, image.center.y - 100);
}];
The transform property expresses an affine transform relative to the center property (or the layer's anchorPoint, if changed).
i'm having the same problem. if i want to translate my label 100 on the y-axis, it will start the animation -50 in the y, then moves it 100 from there. if i move it 200 in the y, it starts the animation -100 in the y, then moves it 200 from there. it's very frustrating.
#stackoverflowmaster, were you ever able to figure this out?
UPDATE: you must uncheck the "Use Auto Layout" option in the file inspector for whatever object you're trying to use. this took me way too long to figure out, hope it saves someone else some time.
I want to rotate a UIImageView, and I am using this code:
-(IBAction)rotateImageView:(id)sender{
photoView.transform = CGAffineTransformMakeRotation(M_PI); //rotation in radians
}
The code works. when I press the button, the image rotates 180 degrees, but if I press it again it doesn't rotate back to its original position, but it stays still. why??
Because you are applying the same transform to the view again, without taking into account any existing transform.
Try this:
photoView.transform = CGAffineTransformRotate(photoView.transform,M_PI);
you have to rotate the imageView from the current rotation to make it original
use this code
CGAffineTransformRotate(photoView.transform, M_PI);
I'm trying to do a simple horizontal flip animation with a bounce effect.
[UIView animateWithDuration:0.4 delay:0 options:UIViewAnimationCurveEaseIn animations:^{
front.layer.transform=CATransform3DMakeRotation(DEGREES_TO_RADIANS(90), -1.0,0.0,0.0); // flip halfway
}
completion:^(BOOL finished) { // swap view
front.alpha=0;
back.alpha=1;
[UIView animateWithDuration:0.5 animations:^{ // flip remaining + bounce
back.layer.transform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(45), 1.0,0.0,0.0); // final + 45
}
completion:^(BOOL finished) {
[UIView animateWithDuration:0.25 animations:^{
back.layer.transform = CATransform3DMakeRotation(DEGREES_TO_RADIANS(-22.5), 1.0,0.0,0.0); // bounce back
}
completion:^(BOOL finished) {
[UIView animateWithDuration:0.125 animations:^{
back.layer.transform = CATransform3DMakeRotation(0, 1.0,0.0,0.0); // final
}];
}];
}];
}];
Works well except for the 'bounce'. The -22.5 rotation transitions to 0 and than back to 22.5 instead of continuing to -22.5.
I've tried various values and also including an intermediate nested block that transitions the bounce to '0' before going to negative. Didn't help. The rotation always animates to a positive instead of a negative angle.
Just as a test, changing the 'final + 45' to a negative angle does however stop the animation at the desired angle. So the angles themselves are ok.
Problem seems to be doing a 'counter clockwise' rotation starting from zero or going trough zero. Values smaller than zero than always get converted to a positive angle.
Independent if the above is the right technique for implementing a bounce effect, how would a (nested) layer animation be constructed that rotates via CATransform3DMakeRotation from a positive (45) to a negative angle (-45)?
You are rotating around the x-axis. Without a perspective on your transform, how would you see the difference between positive and negative angles? Without perspective, both positive and negative rotations look the same (the decrease the height). You can apply perspective to your transform by changing the value in the third row and fourth column of your transform matrix by setting .m34. Search for "Core Animation perspective" and you will find a good explanation.
I ran your code above (on a simple view, filled with orange).
To more easily be able to see the rotation and the difference between positive and negative angles, I changed it so that it rotates around the z-axis.
These are four screenshots that I took during the animation. As you can see, the negative angle works, unless I misunderstood what you were trying to do.
I'm working on a drawing app.
I want the user to be able to "drop" a shape on the screen and then move, resize or rotate it as desired.
The problem is with the rotation. I have the moving and resizing working fine.
I did this before with a rather complex and memory/processor-intensive process, which I am now trying to improve.
I've searched and searched but haven't found an answer similar to what I'm trying to do.
Basically, let's say the user drops a square on the "surface". Then, they tap it and get some handles. They can touch anywhere and pan to move the square around (working already), touch and drag on a resize handle to resize the square (working already), or grab the rotation handle to have the square rotate around its center.
I've looked into drawing the square using UIBezierPath or just having it be a subclass of UIView that I fill.
In either case, I'm trying to rotate the UIView itself, not some contents inside. Every time I try to rotate the view, either nothing happens, the view vacates the screen or it rotates just a little bit and stops.
Here's some of the code I've tried (this doesn't work, and I've tried a lot of different approaches to this):
- (void) rotateByAngle:(CGFloat)angle
{
CGPoint cntr = [self center];
CGAffineTransform move = CGAffineTransformMakeTranslation(-1 * cntr.x, -1 * cntr.y);
[[self path] applyTransform:move];
CGAffineTransform rotate = CGAffineTransformMakeRotation(angle * M_PI / 180.0);
[[self path] applyTransform:rotate];
[self setNeedsDisplay];
CGAffineTransform moveback = CGAffineTransformMakeTranslation(cntr.x, cntr.y);
[[self path] applyTransform:moveback];
}
In case it isn't obvious, the thinking here it to move the view to the origin (0,0), rotate around that point and then move it back.
In case you're wondering, "angle" is calculated correctly. I've also wrapped the code above in a [UIView beginAnimations:nil context:NULL]/[UIView commitAnimations] block.
Is it possible to rotate a UIView a "custom" amount? I've seen/done it before where I animate a control to spin, but in those examples, the control always ended up "square" (i.e., it rotated 1 or more full circles and came back to its starting orientation).
Is it possible to perform this rotation "real-time" in response to UITouches? Do I need to draw the square as an item in the layer of the UIView and rotate the layer instead?
Just so you know, what I had working before was a shape drawn by a set of lines or UIBezierPaths. I would apply a CGAffineTransform to the data and then call the drawRect: method, which would re-draw the object inside of a custom UIView. This UIView would host quite a number of these items, all of which would need to be re-drawn anytime one of them needed it.
So, I'm trying to make the app more performant by creating a bunch of UIView subclasses, which will only get a command to re-draw when the user does something with them. Apple's Keynote for the iPad seems to accomplish this using UIGestureRecognizers, since you have to use two fingers to rotate an added shape. Is this the way to go?
Thoughts?
Thanks!
-(void)rotate{
CGAffineTransform transform;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve:UIViewAnimationOptionBeginFromCurrentState];
myView.alpha = 1;
transform = CGAffineTransformRotate(myView.transform,0.5*M_PI);
[myView setUserInteractionEnabled:YES];
myView.transform = transform;
[UIView commitAnimations];
}
This might help.
for just simple rotation you might leave out the Animation:
-(void)rotate:(CGFloat)angle
{
CGAffineTransform transform = CGAffineTransformRotate( myView.transform, angle * M_PI / 180.0 );
myView.transform = transform;
}
I use a simple NSTimer to control a animation.