UIView frame, bounds and center
Asked Answered
U

6

327

I would like to know how to use these properties in the right manner.

As I understand, frame can be used from the container of the view I am creating. It sets the view position relative to the container view. It also sets the size of that view.

Also center can be used from the container of the view I'm creating. This property changes the position of the view relative to its container.

Finally, bounds is relative to the view itself. It changes the drawable area for the view.

Can you give more info about the relationship between frame and bounds? What about the clipsToBounds and masksToBounds properties?

Ultramicrochemistry answered 19/3, 2011 at 9:57 Comment(1)
This Discussion already solved here. so pls look it here or could see developer Documentation given here developer.apple.com/library/ios/#documentation/uikit/reference/… #1210547 slideshare.net/onoaonoa/cs193p-lecture-5-view-animationBilow
G
588

Since the question I asked has been seen many times I will provide a detailed answer of it. Feel free to modify it if you want to add more correct content.

First a recap on the question: frame, bounds and center and theirs relationships.

Frame A view's frame (CGRect) is the position of its rectangle in the superview's coordinate system. By default it starts at the top left.

Bounds A view's bounds (CGRect) expresses a view rectangle in its own coordinate system.

Center A center is a CGPoint expressed in terms of the superview's coordinate system and it determines the position of the exact center point of the view.

Taken from UIView + position these are the relationships (they don't work in code since they are informal equations) among the previous properties:

  • frame.origin = center - (bounds.size / 2.0)

  • center = frame.origin + (bounds.size / 2.0)

  • frame.size = bounds.size

NOTE: These relationships do not apply if views are rotated. For further info, I will suggest you take a look at the following image taken from The Kitchen Drawer based on Stanford CS193p course. Credits goes to @Rhubarb.

Frame, bounds and center

Using the frame allows you to reposition and/or resize a view within its superview. Usually can be used from a superview, for example, when you create a specific subview. For example:

// view1 will be positioned at x = 30, y = 20 starting the top left corner of [self view]
// [self view] could be the view managed by a UIViewController
UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

When you need the coordinates to drawing inside a view you usually refer to bounds. A typical example could be to draw within a view a subview as an inset of the first. Drawing the subview requires to know the bounds of the superview. For example:

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];    
view2.backgroundColor = [UIColor yellowColor];

[view1 addSubview:view2];

Different behaviours happen when you change the bounds of a view. For example, if you change the bounds size, the frame changes (and vice versa). The change happens around the center of the view. Use the code below and see what happens:

NSLog(@"Old Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"Old Center %@", NSStringFromCGPoint(view2.center));    

CGRect frame = view2.bounds;
frame.size.height += 20.0f;
frame.size.width += 20.0f;
view2.bounds = frame;

NSLog(@"New Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"New Center %@", NSStringFromCGPoint(view2.center));

Furthermore, if you change bounds origin you change the origin of its internal coordinate system. By default the origin is at (0.0, 0.0) (top left corner). For example, if you change the origin for view1 you can see (comment the previous code if you want) that now the top left corner for view2 touches the view1 one. The motivation is quite simple. You say to view1 that its top left corner now is at the position (20.0, 20.0) but since view2's frame origin starts from (20.0, 20.0), they will coincide.

CGRect frame = view1.bounds;
frame.origin.x += 20.0f;
frame.origin.y += 20.0f;
view1.bounds = frame; 

The origin represents the view's position within its superview but describes the position of the bounds center.

Finally, bounds and origin are not related concepts. Both allow to derive the frame of a view (See previous equations).

View1's case study

Here is what happens when using the following snippet.

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

NSLog(@"view1's frame is: %@", NSStringFromCGRect([view1 frame]));
NSLog(@"view1's bounds is: %@", NSStringFromCGRect([view1 bounds]));
NSLog(@"view1's center is: %@", NSStringFromCGPoint([view1 center]));

The relative image.

enter image description here

This instead what happens if I change [self view] bounds like the following.

// previous code here...
CGRect rect = [[self view] bounds];
rect.origin.x += 30.0f;
rect.origin.y += 20.0f;
[[self view] setBounds:rect];

The relative image.

enter image description here

Here you say to [self view] that its top left corner now is at the position (30.0, 20.0) but since view1's frame origin starts from (30.0, 20.0), they will coincide.

Additional references (to update with other references if you want)

About clipsToBounds (source Apple doc)

Setting this value to YES causes subviews to be clipped to the bounds of the receiver. If set to NO, subviews whose frames extend beyond the visible bounds of the receiver are not clipped. The default value is NO.

In other words, if a view's frame is (0, 0, 100, 100) and its subview is (90, 90, 30, 30), you will see only a part of that subview. The latter won't exceed the bounds of the parent view.

masksToBounds is equivalent to clipsToBounds. Instead to a UIView, this property is applied to a CALayer. Under the hood, clipsToBounds calls masksToBounds. For further references take a look to How is the relation between UIView's clipsToBounds and CALayer's masksToBounds?.

Gneiss answered 19/3, 2011 at 9:57 Comment(8)
@Rhubarb You are perfectly right. I will point it out in my answer. Thanks.Ultramicrochemistry
I don't know if I will get an answer but why does the subview move in the negative direction when the bounds origins are changed. Just can't seem to get my head around that bit. Thanks!!Romansh
@Romansh It seems that the view moves in the negative direction but it's not. Internal coordinates of the superview are changed.Ultramicrochemistry
forgive my geometric abilities, if the internal coordinates of the superview are changed to origin (30.0, 20.0), does the point (0,0) lie inside of the blue square or outside of it. I am just trying to track down the changes and make sense of it. Thanks for taking time to answer.Romansh
@flexaddicted: Hi, the slide you added says: "View B's middle in its own coordinate space is: bounds.size.width/2+origin.x" -- why is this the case? Since the title says in its own coordinate space, I would say it is: bounds.size.width/2+bounds.origin.x?? Isn't it??Corneliuscornell
@Corneliuscornell Yes, in fact it is. ;)Ultramicrochemistry
@flexaddicted: hm got a bit confused now, it seems the slide says bounds.size.width/2+bounds.origin.x -- for some reasons it seems I didn't notice the bounds in front of origin.x and hence my comment. Seems the correct answer is: ..+bounds.origin.xCorneliuscornell
Developers mostly constrain views using either 1) storyboards (fine) 2) constraints (fine) 3) superview's frame (not fine) 4) I rarely see them use the superview's bounds. So just to conclude you're saying using superview's frame doesn't make sense, because the view may get rotated and instead the superview's bounds is the right approach. That makes sense but I guess since most of the time we're not dealing with views that are rotated we don't rune into unexpected issues. Right? Q: Is there anytime that actually using the superview's bounds would not be what you want? If so when?Cush
B
140

This question already has a good answer, but I want to supplement it with some more pictures. My full answer is here.

To help me remember frame, I think of a picture frame on a wall. Just like a picture can be moved anywhere on the wall, the coordinate system of a view's frame is the superview. (wall=superview, frame=view)

To help me remember bounds, I think of the bounds of a basketball court. The basketball is somewhere within the court just like the coordinate system of the view's bounds is within the view itself. (court=view, basketball/players=content inside the view)

Like the frame, view.center is also in the coordinates of the superview.

Frame vs Bounds - Example 1

The yellow rectangle represents the view's frame. The green rectangle represents the view's bounds. The red dot in both images represents the origin of the frame or bounds within their coordinate systems.

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here


Example 2

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here


Example 3

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here


Example 4

This is the same as example 2, except this time the whole content of the view is shown as it would look like if it weren't clipped to the bounds of the view.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

enter image description here


Example 5

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (280, 70)
    width = 80
    height = 130

enter image description here

Again, see here for my answer with more details.

Biocellate answered 8/3, 2015 at 6:11 Comment(4)
Thanks Suragch. It is really very clear picture of frame and bound difference. I really appreciate your effort.Calomel
All the stuff that I want to see in one short and concise answer. Thanks!Powers
Awesome! For Example 3: I don't get it. you only moved your frame's origin a little bit, how does that change your image's rotation?Cush
@asma22, In example 3 I was just trying to show that when you rotate an image the frame changes but the bounds don't. See my fuller answer.Biocellate
Z
89

I found this image most helpful for understanding frame, bounds, etc.

enter image description here

Also please note that frame.size != bounds.size when the image is rotated.

Zawde answered 12/10, 2012 at 0:50 Comment(5)
A picture worth thousand words.Phytoplankton
The best possible explanationVulgus
@Erben Mo: Hi, the slide you added says: "View B's middle in its own coordinate space is: bounds.size.width/2+origin.x" -- why is this the case? Since the title says in its own coordinate space, I would say it is: bounds.size.width/2+bounds.origin.x?? Isn't it??Corneliuscornell
What is the source of this image? Link?Postilion
@Postilion It's from Stanford's CS193p course on iTunesU found here: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fallDeterioration
V
5

I think if you think it from the point of CALayer, everything is more clear.

Frame is not really a distinct property of the view or layer at all, it is a virtual property, computed from the bounds, position(UIView's center), and transform.

So basically how the layer/view layouts is really decided by these three property(and anchorPoint), and either of these three property won't change any other property, like changing transform doesn't change bounds.

Vachon answered 21/10, 2014 at 5:51 Comment(0)
U
3

There are very good answers with detailed explanation to this post. I just would like to refer that there is another explanation with visual representation for the meaning of Frame, Bounds, Center, Transform, Bounds Origin in WWDC 2011 video Understanding UIKit Rendering starting from @4:22 till 20:10

Unsaddle answered 31/10, 2015 at 19:16 Comment(0)
R
0

After reading the above answers, here adding my interpretations.

Suppose browsing online, web browser is your frame which decides where and how big to show webpage. Scroller of browser is your bounds.origin that decides which part of webpage will be shown. bounds.origin is hard to understand. The best way to learn is creating Single View Application, trying modify these parameters and see how subviews change.

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 200.0f, 200.0f, 400.0f)];
[view1 setBackgroundColor:[UIColor redColor]];

UIView *view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];
[view2 setBackgroundColor:[UIColor yellowColor]];
[view1 addSubview:view2];

[[self view] addSubview:view1];

NSLog(@"Old view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"Old view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));

// Modify this part.
CGRect bounds = view1.bounds;
bounds.origin.x += 10.0f;
bounds.origin.y += 10.0f;

// incase you need width, height
//bounds.size.height += 20.0f;
//bounds.size.width += 20.0f;

view1.bounds = bounds;

NSLog(@"New view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"New view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));
Rodrique answered 3/4, 2015 at 20:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.