I have a view in which I am doing some specific drawings in drawRect. These drawings are dynamic and are based on the view's width and height. Then, the view which contains it applies a rotation transformation to it. However this transformation seems to adjust the values for my view's frame which impacts my drawing in drawRect.
NSLog(#"before:%f,%f,%f,%f",button.frame.origin.x,button.frame.origin.y,button.frame.size.width,button.frame.size.height);
CGAffineTransform currentTransform = button.transform;
CGAffineTransform transformRotate = CGAffineTransformMakeRotation(degreesToRadians);
button.transform = transformRotate;
NSLog(#"after:%f,%f,%f,%f",button.frame.origin.x,button.frame.origin.y,button.frame.size.width,button.frame.size.height);
Here is the output:
before:50.000000,100.000000,150.000000,50.000000
after:65.849365,47.548096,118.301262,154.903809
Is this correct behaviour or am I applying the transformation incorrectly?
See the reference documentation on UIView's frame property;
frame
The frame rectangle, which describes the view’s location and size in
its superview’s coordinate system.
#property(nonatomic) CGRect frame
Warning
If the transform property is not the identity transform, the value of
this property is undefined and therefore should be ignored.
Despite that warning, things work as intended. Once a transformation (other that identity) is applied, the frame usually results into the projection rectangle of the original view.
But then again, you should not ignore that warning if you really want to find out about the frame with the applied transformation and use CGRectApplyAffineTransform for properly getting it.
Related
I have a simple test app that has one view, one view controller, and all of this is instantiated via a standard storyboard. When I run my app and pause on a breakpoint in my view controller I can see that the following values are set on the view:
self.view.layer.position = (CGPoint) (x=160, y=294)
self.view.layer.frame = (CGRect) (origin=(x=0, y=20) size=(width=320, height=548))
self.view.layer.visibleRect = (CGRect) (origin=(x=0, y=0) size=(width=320, height=548))
I understand the initial origin value for the frame (assuming the value of 20 is an offset for the status bar), but where is the 160/294 value coming from for the layer's position? I'm baffled by this one.
This is because a CALayer's position property is relative to its anchorPoint. By default, the anchorPoint is set to (0.5, 0.5), which represents the center of the layer's bounds.
If you're trying to perform very basic positioning changes programmatically, I'd stay away from your view's layer property, since UIView has positioning properties of its own.
How is a CALAyer.frame related to its UIView.frame? (in this case specifically a UIImageView.frame).
Given that the values for a CALayer.frame potentially differ from its UIView.frame following a CAtransform3D transformation, do they no longer have any connection? (and subsequently, should I be more concerned about managing the dimensions of my CALayer rather than my UIImageView in my superview?).
If you are working with Core Animation and layers, you should focus on the following CALayer properties:
position
bounds
anchorPoint
transform
A quote from Apple Technical Q&A QA1620 available here:
Q: When I try to animate the frame of a CALayer nothing happens. Why?
A: The frame property of a CALayer is a derived property, dependent on
the position, anchorPoint, bounds and transform of the layer. Instead
of animating the frame, you should instead animate the position or
bounds, depending on what effect you are trying to accomplish.
I have a problem I've run into with the UIView method convertRect: fromView: method. Here is the situation:
I have an overwritten the UIView class to create a view that rotates with the user's movement(very similar to the TaskRabbit spinner). To create the rotation, over I added an additional view to my subclassed view, and I rotated that view. The rotated view contains additional subviews that obviously rotate with the rotated subview. The problem is, after the subview has been rotated, I need to find where those additional subviews are, with respect to the original overritten view - not the rotated view. To do this, in my UIView class, I have the following:
[self convertRect:currentView.frame fromView:rotationView];
However, when I print out the frame of the converted rect, the coordinates are not accurate. Has anyone run into this issue where the convertRect: fromView: isn't accurate after the view is rotated?
Edit
Specifically, about the points being not accurate, I can't even see the relationship between what is should be and what it is-ie off by an specific angle, x/y flipped etc. For example, the point that should be (25, 195) is returned at (325.25, 273.16)
I'm assuming that you are rotating your views by applying a transform to them (either a CGAffineTransform to the view or a CATransform3D to the layer). This is what is causing the problem with your frame. The documentation for UIView frame says:
Warning If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored.
As you've already seen, the value of the frame is undefined. You can still use the center and bounds properties though.
I have a UIImageView that can be resized by pinching in and out (Example: view.frame.size.width+10). The image of the Image View can also be rotated (CGAffineTransformMakeRotate). Okay, here is the problem: When I resize the UIImageView AFTER having had applied a Rotate Transform the view resizes abnormally (inversly (shrink when it should grow, vice-versa) or at enormous resize unit increments). How can I resize my UIImageView in a consistent manner whether or not a CGAffineTransform is applied?
There's a warning in the documentation for UIView that says, for the frame property:
Warning: If the `transform` property is not the identity transform, the value of this property is undefined and therefore should be ignored.
Use the bounds and center properties instead; they remain viable after a transform is applied.
I rotate/scale a UIVIew using [UIView transform:] and this works well. However, as soon as I change the view's frame origin the contents of the view begins to scale 'weirdly' even though I am not performing any further CGAffineTransforms.
Why does this occur? How can I prevent it?
Update 1:
The docs suggest that the frame is invalid after a transform. Can I move the view via it's 'center' property instead?
Update 2:
Setting the views center did allow me to translate the view successfully after a transform had been applied.
Can I move the view via it's 'center' property instead?
The documentation defines the center property as:
The center of the frame.
and says:
The center is specified within the coordinate system of its superview.
I'd try it.
From the UIView docs:
transform:
Warning: If this property is not the identity transform, the value of
the frame property is undefined and
therefore should be ignored.
The center property is just a convenience method that really resets the frame's origin.
Edit: appended to answer comment:
If you're using the transform property and want to reposition your view, you have to concatenate the translation to your transform using:
view.transform = CGAffineTransformTranslate(view.transform, tx, tx);