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.
Related
when I use: ImageView.transform = CGAffineTransformRotate(ImageView.transform, rotation); everytime I rotate imageView and I NSLog(#"x:%f y:%f", ImageView.frame.orgin.x, ImageView.frame.orgin.y), x and y always change value?? Why?
Well the .frame.origin is the top left corner of you UIImageView and since you are rotating it the top left corner is moving. If you access the .center it should stay the same.
The UIView documentation states that
Warning: If this property is not the identity transform, the value of the frame property is undefined and therefore should be ignored.
regarding the transform property of a UIView. Since you are assigning to the transform it is most likely not the identity transform any more, hence the frame value is undefined, and should be ignored.
On iOS, if we change a view's frame, we change its bounds, and if we change its bounds, we change its frame.
But we can change the internal coordinate system of a view by:
CGRect b = v.bounds; // v is the UIView object
b.origin.x = 10000;
b.origin.y = 10000;
v.bounds = b;
and now, the top left point of the view is a coordinate of (10000, 10000). Is this also possible by merely changing frame and center but not bounds?
On iOS, if we change a view's frame, we change its bounds, and if we change its bounds, we change its frame.
That's half true. Only the sizes of those two rects are bound together. From the docs:
The size portion of the frame and bounds rectangles are coupled together so that changing the size of either rectangle updates the size of both.
That doesn't mention the origins. So your example will modify the internal coordinate system's origin without changing its position in the superview's coordinate system. You can't achieve that behavior via the frame or center properties; they only affect the the view's position in its superview's coordinate system.
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 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.
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);