21

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

Marin Todorov
  • 6,377
  • 9
  • 45
  • 73

7 Answers7

47

I use this in Objective C:

CGRect transformedBounds = CGRectApplyAffineTransform(view.bounds, view.transform);

or in Swift 4:

let transformedBounds = view.bounds.applying(view.transform)
Michael
  • 9,639
  • 3
  • 64
  • 69
Nikso
  • 471
  • 1
  • 4
  • 3
12

[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.

DD_
  • 7,230
  • 11
  • 38
  • 59
drawnonward
  • 53,459
  • 16
  • 107
  • 112
  • 1
    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 – Marin Todorov Apr 23 '10 at 06:43
  • 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 – Marin Todorov Apr 23 '10 at 08:20
  • Also note that the center property is supposed to work, even with non-identity transforms. – Olie Jul 17 '14 at 23:56
4

Old question, but bumped into here, after searching a solution and tons of attempts. It was simple;

view.layer.frame has all transformations applied and you'll get the size from view.layer.frame.size easily.

-- below here is not an answer to this question - -

And for my problem, I was trying to calculate new center value after changing layer.anchorPoint of my rotated view, so it doesn't move. And finally did it like this;

CGPoint topLeft = [self.superview convertPoint:CGPointMake(0, 0) fromView:self];
self.layer.anchorPoint = CGPointMake(0, 0);
self.center = topLeft;

for reverse

CGPoint center = [self.superview convertPoint:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) fromView:self];
self.layer.anchorPoint = CGPointMake(.5, .5);
self.center = center;

finally.

Furkan Mustafa
  • 794
  • 7
  • 12
3

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

Ashley Clark
  • 8,813
  • 3
  • 35
  • 35
  • 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) – Marin Todorov Apr 23 '10 at 06:40
2

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
  • 71
  • 2
0

But you apply a rotating transform, it don't get right size by CGPathGetBoundingBox.

applezqp
  • 1
  • 4
0

If you applied the CGAffineTransform the view's .layer then the adjusted CGRect region after scale and/or translation transforms is simply view.layer.frame

Albert Renshaw
  • 17,282
  • 18
  • 107
  • 195