views:

435

answers:

3

I was surprised not to find an answer to this question, maybe is something very simple I somehow overlook :

How to get the real size of an UIView after I apply a CGAffineTransform to it?

eg.

my UIView has size 300 x 200, I apply a scaling transform let's say factor 2 both horizontal and vertical, so the UIView now takes 600 x 400 on the screen, but it's bounds and it's layer's bounds are still returning a size of 300 x 200 ... where do I find the real size of the UIView ?

ps. forgot to mention I want to also rotate the uiview. If I apply only scaling CGSizeApplyAffineTransform works great, but when there's also rotation, then it does not work properly.

Edit: drawnonward pointed me in the right direction, I just refined a bit the code to compile and here it is :

UIView* view = (your view being transformed);
CGAffineTransform trans = (view.transform or create a new transformation);

CGRect rect = [view bounds];
CGMutablePathRef path = CGPathCreateMutable();
rect.origin = CGPointZero;
CGPathAddRect(path , &trans , rect);
rect = CGPathGetBoundingBox( path );
CGPathRelease( path );

Now rect.size contains the dimensions of the view with the transformation applied Thanks again to drawnonward

A: 

Use CGSizeApplyAffineTransform(size, transform) and it will return a transformed size. There are similar CGPoint and CGRect functions as well.

Ashley Clark
That's not working correctly when CGSizeApplyAffineTransform includes also rotation, but otherwise you are right in the cases there's only scaling applied. (my mistake I didn't include also rotation in my question)
Ican Zilb
+1  A: 

[myView frame] returns the frame of the view as seen by the parent, for layout and relative sizes. [myView bounds] returns the bounds of the view as seen by itself, for drawing. If you have transforms applied to multiple views, you can use convertRect: to or from a view.

Edit:

Maybe something like this.

CGRect rect = [view bounds];
CGPathRef path = CGPathCreateMutable();
rect.origin = CGPointZero;
CGPathAddRect( rect , [view transform] );
rect = CGPathGetBoundingBox( path );
CGPathRelease( path );

The use [view center] to find the position in the superview.

drawnonward
Here's the documentation about "frame" from the apple docs: Warning: If the transform property is not the identity transform, the value of this property is undefined and therefore should be ignored. So, frame is out of question when there's transformation applied.And "bounds" returns always the original size
Ican Zilb
Indeed! Argh, this function libraries that I always forget about - CGPathGetBoundingBox was the trick. I edited the question with the working code, thanks a lot man
Ican Zilb
A: 

Simpler: A view with (bounds) size s to which transform tr is applied has resulting size:

CGSizeMake(s.width*hypotf(tr.a, tr.b), s.height*hypotf(tr.c, tr.d))

However, if view's superview or any ancestor view has any non-unit transform applied, this size makes little sense in absolute terms.

If you want the absolute size of a view in window coordinates after any arbitrary transform has been applied to that view or its superviews, you should first compute the absolute transform matrix by composing all the view transform up to the root window, and then apply the above formula to the result.

Marco B