Rotating a view in iOS - ios

I have a UIView in my view. Right now I have a button moving the UIView on it's y axis. Here is my code
CGRect frame2 = self.test22.frame;
frame2.origin.y -= 1.f/[UIScreen mainScreen].scale; //however many pixels to the right..
self.test22.frame = frame2;
But how can I rotate it? Except using the x or y axis. I want to be able to move the UIView by rotation by 1.f.

To Rotate the UIView create the object of UIView (*view) and make transform on it
Lets to rotate the view 90 degree use below code
CGAffineTransform r_transform = CGAffineTransformIdentity;
r_transform = CGAffineTransformRotate(r_transform,DegreeYoRadians(90));
view.transform = r_transform;

Welcome to SO. You want to look at the UIView method animateWithDuration, and the view's transform property. You'd apply a rotation transform to the view in your animation block. Note that if you change a view's transform, you should not read or write the frame property. Instead use the center property to change the position and the bounds.size property if you need to change the size.
Your code might look like this:
[UIView animateWithDuration: .25
animations: ^
{
self.test22.transform = CGAffineTransformMakeRotation(M_PI/2);
CGPoint center = self.test22.center;
center.y -= 1;
self.test22.center = center;
}
];
EDIT:
I have no idea what you mean when you say "I want to be able to move the UIView by rotation by 1.f." Rotating a view is not moving it, it's rotating it. And rotation is expressed as an angle, not a value like "1". Furthermore, the angle is in radians, where π is 180 degrees, π/2 is 90 degrees, and 2π is a full-circle rotation (or no change, since it puts the rotation back at it's original value.) You have to think in terms of fractions of 2π when you do rotations. Or you can use degrees and convert to radians, where:
degrees = radians * 180/π
Also, your code that moves the view will only change the view's position by half a point on retina displays which doesn't make much sense.

Related

Rotate view around y axis

How to rotate a UIView around its Y axis using CGAffineTransform (or other)?
I've tried for example with:
self.image.transform = CGAffineTransform(rotationAngle: 2*CGFloat.pi)
but only rotate around Z axis.
That is not what a CGAffineTransform is. You want a CATransform3D.
But you cannot set that on a UIView transform. You will have to set it on the view's layer (or on some CALayer).
https://developer.apple.com/documentation/quartzcore/calayer/1410836-transform

Why does a view changes position when rotating it using CGAffineTransformMakeRotation

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;
}];

Animating the bounds property of a UIView

According to the Apple documentation available here the bounds property of a UIView can be animated.
In order to programmatically rotate one of my views (in this case from portrait to landscape), I implemented the following code:
float w = controlsView.bounds.size.width;
float h = controlsView.bounds.size.height;
CGAffineTransform T = CGAffineTransformMakeRotation(M_PI/2);
UIViewContentMode oldContentMode = controlsView.contentMode;
controlsView.contentMode = UIViewContentModeRedraw;
[UIView animateWithDuration:1.0 animations:^{
controlsView.bounds = CGRectMake(0, 0, h, w);
controlsView.transform = T;
}];
controlsView.contentMode = oldContentMode;
I added the two instructions for contentMode because I have read somewhere on StackOverflow that contentMode must be set to that value in order for a UIView to redraw the content while the bounds property is modified (however, in this case it does not affect the behaviour in any way).
The problem of that code is that UIView is not resized with an animation but all at once.
Executing that code, the UIView is first resized (without animation) then rotated with an animation.
How can I animate the resizing?
-- UPDATE --
I tried to combine a scaling and rotating transformation. The UIView rotates and scales in an animation, but at the end its bounds property does not change: even if it has been rotated to a landscape orientation (which should be 568x320 on my iPhone), its width and height stay at the portrait values (320x568). Indeed, the UI controls on the controlsView are deformed (wrong aspect ratio) and appears stretched.
This worked for me using UIViewAnimationOptions.LayoutSubviews (Swift):
UIView.animateWithDuration(1.0,delay:0.0,
options:UIViewAnimationOptions.LayoutSubviews,
animations:{ () -> Void in
myView.transform = myRotationTransform
myView.bounds = myBounds
}, completion: nil)
(no explicit scaling nor changing contentMode)
The problem is that when you set a transform property, all other transforms (bounds) are overwritten. To fix it you have to create one transform that combines scaling and rotating.
Example:
CGAffineTransform scaleTransform = CGAffineTransformMakeScale(0.5, 0.5);
[UIView animateWithDuration:1.0 animations:^
{
controlsView.transform = CGAffineTransformRotate(scaleTransform, M_PI/2);
}];
You will need to calculate the scaling X and Y values based on the size you want to have at the end of the animations. You might also want to change the anchorPoint property to set a center point used for scaling (controlsView.layer.anchorPoint).
Animating your bounds doesn't change its value. It reverts to its original value once the animation ends.
Change the value of the bounds to the final value once the animation is over. I'll solve the trouble.

Reseting rotation of UIView to 0

How can I reset rotation of my View back to zero while keep other transformations on that view unchanged.
I cant use:
[myView setTransform:CGAffineTransformIdentity]
as it will rest all the other transforms too.
Or I just want the frame of the view if its rotation was 0.
myView.transform = CGAffineTransformRotate(myView.transform, -currentRotationAngle);
this will take the current transform, and rotate it to 0 degrees
Edit: i think you will need to rotate by the inverse of your current rotation value, not just set it to 0
To reset the rotation while keeping the transition you could try this code:
CGAffineTransform inverse = CGAffineTransformInvert(myView.affineTransform);
inverse.tx = 0;
inverse.ty = 0;
myView.transform = inverse;

How to compose Core Animation CATransform3D matrices to animate simultaneous translation and scaling

I want to simultaneously scale and translate a CALayer from one CGrect (a small one, from a button) to a another (a bigger, centered one, for a view). Basically, the idea is that the user touches a button and from the button, a CALayer reveals and translates and scales up to end up centered on the screen. Then the CALayer (through another button) shrinks back to the position and size of the button.
I'm animating this through CATransform3D matrices. But the CALayer is actually the backing layer for a UIView (because I also need Responder functionality). And while applying my scale or translation transforms separately works fine. The concatenation of both (translation, followed by scaling) offsets the layer's position so that it doesn't align with the button when it shrinks.
My guess is that this is because the CALayer anchor point is in its center by default. The transform applies translation first, moving the 'big' CALayer to align with the button at the upper left corner of their frames. Then, when scaling takes place, since the CALayer anchor point is in the center, all directions scale down towards it. At this point, my layer is the button's size (what I want), but the position is offset (cause all points shrank towards the layer center).
Makes sense?
So I'm trying to figure out whether instead of concatenating translation + scale, I need to:
translate
change anchor point to upper-left.
scale.
Or, if I should be able to come up with some factor or constant to incorporate to the values of the translation matrix, so that it translates to a position offset by what the subsequent scaling will in turn offset, and then the final position would be right.
Any thoughts?
You should post your code. It is generally much easier for us to help you when we can look at your code.
Anyway, this works for me:
- (IBAction)showZoomView:(id)sender {
[UIView animateWithDuration:.5 animations:^{
self.zoomView.layer.transform = CATransform3DIdentity;
}];
}
- (IBAction)hideZoomView:(id)sender {
CGPoint buttonCenter = self.hideButton.center;
CGPoint zoomViewCenter = self.zoomView.center;
CATransform3D transform = CATransform3DIdentity;
transform = CATransform3DTranslate(transform, buttonCenter.x - zoomViewCenter.x, buttonCenter.y - zoomViewCenter.y, 0);
transform = CATransform3DScale(transform, .001, .001, 1);
[UIView animateWithDuration:.5 animations:^{
self.zoomView.layer.transform = transform;
}];
}
In my test case, self.hideButton and self.zoomView have the same superview.

Resources