Layout
We have seen that a subview moves when its superview’s bounds origin is changed. But what happens to a subview when its superview’s bounds size is changed? (And remember, this includes changing the superview’s frame size.)
Of its own accord, nothing happens. The subview’s bounds and center haven’t changed, and the superview’s bounds origin hasn’t moved, so the subview stays in the same position relative to the top left of its superview. In real life, however, that often won’t be what you want. You’ll want subviews to be resized and repositioned when their superview’s bounds size is changed. This is called layout.
Layout is performed in two primary ways, which can be combined:
Automatic layout
Automatic resizing of subviews depends on the superview’s autoresizesSubviews property. To turn off a view’s automatic resizing altogether, set this property to NO. If it is YES, then a subview will respond automatically to its superview’s being resized, in accordance with the rules prescribed by the subview’s autoresizingMask property value.
Manual layout
The superview is sent the layoutSubviews message whenever it is resized; so, to layout subviews manually,provide your own subclass and override layoutSubviews.If you’re going to use both approaches, automatic resizing is performed before layoutSubviews is called.
You should never call layoutSubviews yourself. Instead, if you wish to trigger layout, send setNeedsLayout to the view. This will cause the layout procedures to be followed at the next appropriate moment. Alternatively, if you really need layout to occur right this moment, send the view the layoutIfNeeded message; this may cause the layout of the entire view tree, not only below but also above this view, and is probably not a very common thing to do.
Automatic resizing is a matter of conceptually assigning a subview “springs and struts.” A spring can stretch; a strut can’t. Springs and struts can be assigned internally or externally. Thus you can specify, using internal springs and struts, whether and how the view can be resized, and, using external springs and struts, whether and how the view can be repositioned.
For example:
1)Imagine a subview that is centered in its superview and is to stay centered, but is to resize itself as the superview is resized. It would have struts externally and springs internally.
2)Imagine a subview that is centered in its superview and is to stay centered, and is not to resize itself as the superview is resized. It would have springs externally and struts internally.
3)Imagine an OK button that is to stay in the lower right of its superview. It would have struts internally, struts externally to its right and bottom, and springs externally to its top and left.
4)Imagine a text field that is to stay at the top of its superview. It is to widen as the superview widens.It would have struts externally; internally it would have a vertical strut and a horizontal spring.
When editing a nib file, you can experiment with assigning a view springs and struts in the Size inspector (Autosizing). A solid line externally represents a strut; a solid line internally represents a spring. A helpful animation shows you the effect on your view’s position as its superview is resized.
In code, a combination of springs and struts is set through a view’s autoresizingMask property. It’s a bitmask, so you use logical-or to combine options. The options, with names that start with “UIViewAutoresizingFlexible”, represent springs; whatever isn’t specified is a strut. The default is UIViewAutoresizingNone, meaning all struts.
To demonstrate autoresizing, I’ll start with a view and two subviews, one stretched across the top, the other confined to the lower right:
UIView* v1 = [[UIView alloc] initWithFrame:CGRectMake(100, 111, 132, 194)];
v1.backgroundColor = [UIColor colorWithRed:1 green:.4 blue:1 alpha:1];
UIView* v2 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 132, 10)];
v2.backgroundColor = [UIColor colorWithRed:.5 green:1 blue:0 alpha:1];
UIView* v3 = [[UIView alloc] initWithFrame:CGRectMake(v1.bounds.size.width-20,
v1.bounds.size.height-20,
20, 20)];
v3.backgroundColor = [UIColor colorWithRed:1 green:0 blue:0 alpha:1];
[self.window addSubview: v1];
[v1 addSubview: v2];
[v1 addSubview: v3];
// ... insert autoresizing settings here ...
[v1 release]; [v2 release]; [v3 release];
Into that example, I’ll insert code applying strings and struts to the two subviews to make them behave like the text field and the OK button I was hypothesizing earlier:
v2.autoresizingMask = UIViewAutoresizingFlexibleWidth;
v3.autoresizingMask =
UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleLeftMargin;
Now I’ll resize the superview, thus bringing autoresizing into play; as you can see, the subviews remain pinned in their correct relative positions:
CGRect f = v1.bounds;
f.size.width += 40;
f.size.height -= 50;
v1.bounds = f;