Adopting Auto Layout

Views that are aware of Auto Layout can coexist in a window with views that are not. That is, an existing project can incrementally adopt Auto Layout features.

This works through the property translatesAutoresizingMaskIntoConstraints. When this property is YES, which it is by default, the autoresizing mask of a view is translated into constraints. For example, if a view is configured as in Figure 6-1 and translatesAutoresizingMaskIntoConstraints is YES, then the constraints |-20-[button]-20-| and V:|-20-[button(20)] are added to the view’s superview. The net effect is that unaware views behave as they did in versions of OS X prior to 10.7.

Figure 6-1  Button layout using springs and struts

If you move the button 15 points to the left (including by calling setFrame: at runtime), the new constraints would be |-5-[button]-35-| and V:|-20-[button(20)].

For views that are aware of Auto Layout, in most circumstances you will want translatesAutoresizingMaskIntoConstraints to be NO. This is because the constraints generated by translating the autoresizing mask are already sufficient to completely specify the frame of a view given its superview’s frame, which is generally too much. For example, this will prevent a button from automatically assuming its optimal width when its title is changed.

The principal circumstance in which you should not call setTranslatesAutoresizingMaskIntoConstraints: is when you are not the person who specifies a view’s relation to its container. For example, an NSTableRowView instance is placed by NSTableView. It might do this by allowing the autoresizing mask to be translated into constraints, or it might not. This is a private implementation detail. Other views on which you should not call setTranslatesAutoresizingMaskIntoConstraints: include an NSTableCellView, a subview of NSSplitView, an NSTabViewItem’s view, or the content view of an NSPopover, NSWindow, or NSBox. For those familiar with classic Cocoa layout: If you would not call setAutoresizingMask: on a view in classic style, you should not call setTranslatesAutoresizingMaskIntoConstraints: under Auto Layout.

If you have a view that does its own custom layout by calling setFrame:, your existing code should work. Just don’t call setTranslatesAutoresizingMaskIntoConstraints: with the argument NO on views that you place manually.

To provide additional compatibility, the entire constraint-based layout system is not active at all until you install a constraint on a view. Typically this is not something you should be concerned with, but if your previous layout was delicate in that you had problems you fixed by figuring out in what order the framework called methods, you may find that these problems are back under constraint-based layout. Hopefully in most cases the easiest solution will be to adopt constraint-based layout for the affected views. If you’re a framework author providing custom views and want to avoid engaging constraint-based layout in a window, you can do any necessary work in updateConstraints. This method is not called until constraint-based layout is engaged. Furthermore, one of the purposes of updateConstraints is that it has a well-defined timing, similar to awakeFromNib, so you may find your problems are easier to resolve under Auto Layout.

There is an edge case to be aware of. When you implement a view, you might implement all your constraint setup in a custom updateConstraints method. However, because the constraint based system engages lazily, if nothing installs any constraint, your updateConstraints method will never be invoked. To avoid this problem, you can override requiresConstraintBasedLayout to return YES to signal that your view needs the window to use constraint based layout.


Did this document help you? Yes It's good, but... Not helpful...