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
Related
I am building a custom UIView that you can rotate and resize. I can resize the UIView by dragging the corners of the UIView. I calculate how much I have dragged then change the frame of the UIView accordingly.
However, I am running into problems once I added a rotation gesture recognizer to the view. If I rotate or apply a transform to the view, I no longer know how to calculate drag distance and change the frame of the view. How could I calculate the width and height change between my new view and the original view when things are put at an added angle or if they have some other transform, like a translation transform?
I thought of possibilities to set the view's transform back to .identity, change the size of the view, then re-apply its transform, but I'm not sure how to actually go about implementing this.
After applying transform you can not use frame
You have two options
1) First Calculate everything using center of your view
2) As you know apply identity and change frame
for point 2 I have added example that might helpful to you
let transform = imageView.transform
imageView.transform = CGAffineTransform.identity
var rect: CGRect = imageView.frame
rect = // Change Rect here
imageView.frame = rect // Assign it
imageView.transform = transform // Apply Transform
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.
I am trying to flip a scaled and rotated uiview on the horizontal axis.
Here is the code being used -
CGFloat xScale = selectedFrame.transform.a;
CGFloat yScale = selectedFrame.transform.d;
selectedFrame.layer.transform = CATransform3DScale(CATransform3DMakeRotation(M_PI, 0, 1, 0),xScale, yScale,-1);
The output of this is that the view flips properly and the original scale factor is also manitained but the rotation isnt.
Here are the images to explain the problem -
Original Image (The tiger view has to be flipped on the horizontal axis) -
Flipped image after above code (see that the scale is maintained but the rotation angle isnt and the image s flipped properly) -
Any help would be really appreciated!
To flip the image you are using a rotation of M_PI around the Y axis. To rotate the image, you need to apply another different rotation around the Z axis. These are two different transforms. You can combine them using CATransform3DConcat. Then you can scale the resulting transform.
CATransform3D transform = CATransform3DConcat(CATransform3DMakeRotation(zRotation, 0, 0, 1),CATransform3DMakeRotation(M_PI, 0, 1, 0));
[layer setTransform:CATransform3DScale(transform,xScale, yScale,1)];
The problem with your original code is that you are only applying the Y axis transform.
I'm sure there is a more elegant way to do this, but this works on my simulator.
I have a problem. I'm working on making a game. As part of my game I need images to be rotated and then moved in the direction of the rotated angle inside a game loop (using an NSTimer). In essence I'm trying to create the effect of launching a projectile. The code works fine when moving in perpendicular directions such as 0, 90, 180, 270, and 360 degrees, but any other angle and the image starts to glitch out. The object on the screen maintains its correct bounds and contents, but the actual displayed image disappears. Does anybody know what the problem is or someway I could get around it? If needed, I can make and post a video of my problem so you can see what I'm talking about.
Here is a sample of the code I'm using. The "background" variable is just a UIImageView:
angle = 60;
background.transform = CGAffineTransformRotate(object.transform, angle*M_PI/180); //converts degrees to radians and rotates the image
background.frame = CGRectMake( background.frame.origin.x + cos(angle*m_PI/180)*32; background.frame.origin.y -sin(angle*M_PI/180)*32, background.frame.size.width, background.frame.size.height); //moves the image in the direction of the angle
For starters, there is a semicolon after the x origin in your CGRect instead of a comma. Was that just a typo?
The UIView documentation for frame states:
Warning: If the transform property is not the identity transform, the
value of this property is undefined and therefore should be ignored.
Changes to this property can be animated. However, if the transform
property contains a non-identity transform, the value of the frame
property is undefined and should not be modified. In that case, you
can reposition the view using the center property and adjust the size
using the bounds property instead.
So there you have it, you should not be trying to change the frame when setting a custom transform. You are only trying to adjust the position of the view anyway so just modify your code to adjust center instead of the origin coordinates.
To change the size, you can use the bounds.
CGRect bounds = myView.bounds;
bounds.size.width = whatever;
bounds.size.height = whatever;
myView.bounds = bounds;
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.