Dividing Responsibility Between Controllers and Views
The Cocoa Auto Layout architecture distributes responsibility for layout between controllers and views. Rather than you writing a monolithic, omniscient, controller that calculates where views need to go for a given geometry, views become more self-organizing. This approach reduces the complexity of controller logic, and makes it easier to redesign views without requiring corresponding changes to the layout code.
A View Specifies its Intrinsic Content Size
Leaf-level views such as buttons typically know more about what size they should be than does the code that is positioning them. This is communicated through the method intrinsicContentSize, which tells the layout system that there is some content it doesn't natively understand in a view, and how large that content intrinsically is. This method is overridden by view subclassers, and is called by the layout system. A typical example implementor would be a single line text field. The layout system does not understand text - it must just be told that there's something in the view, and that that something will require a certain amount of space if not clipped.
The layout system calls intrinsicContentSize, and will set up constraints that specify (1) that the opaque content should not be compressed or clipped, (2) that the view prefers to hug tightly to its content.
A view can implement intrinsicContentSize to return absolute values for its width and height, or NSViewNoInstrinsicMetric for either or both to indicate that it has no intrinsic metric for a given dimension.
Correct implementations of intrinsicContentSize are illustrated in the following examples.
The intrinsic size for a push button is dictated by its title and image. A button’s
intrinsicContentSizemethod should return a size with width and height that ensure that the title text is not clipped and that all the image is visible.A horizontal slider, has an intrinsic height, but no intrinsic width—the slider artwork has no intrinsic best width. A horizontal
NSSliderobject returns{NSViewNoInstrinsicMetric, <slider height>}. Any user of a slider will have to provide constraints that govern the width of the slider.A container, such as an instance of
NSBox, has no intrinsic content size and returns{ NSViewNoInstrinsicMetric, NSViewNoInstrinsicMetric }. Its subviews may have intrinsic content sizes, but the subviews’ content is not intrinsic to the box itself.
A Controller Specifies How Important the Intrinsic Size Is
Although a view specifies its intrinsic content size, the user of the view says how important it is. For example, by default, a push button:
Strongly wants to hug its content in the vertical direction (buttons really ought to be their natural height)
Weakly hugs its content horizontally (extra side padding between the title and the edge of the bezel is acceptable)
Strongly resists compressing or clipping content in both directions
In the scope bar in Finder, however, the buttons only weakly resist compressing content in the horizontal direction. (You can make the window small enough that buttons start truncating their contents.) Thus, Finder should lower the priority with which these buttons resist compressing content.
You set the hugging and compression priorities for a view using setContentHuggingPriority:forOrientation: and setContentCompressionResistancePriority:forOrientation: respectively. By default, all AppKit-supplied views have a value of either NSLayoutPriorityDefaultHigh or NSLayoutPriorityDefaultLow.
Views Must Tell the Auto Layout System if Their Intrinsic Size Changes
Although the Auto Layout architecture reduces the burden on the implementer of a controller class, it may slightly increase the burden on the implementer of a view class. If you implement a custom view class, you should determine whether the view has an intrinsic size, and if so implement intrinsicContentSize to return a suitable value.
In addition, if a property of a view changes and that change affects the intrinsic content size, the view must call invalidateIntrinsicContentSize so that the layout system notices the change and can re-layout. In the implementation of your view class, you must ensure that if the value of any property upon which the intrinsic size depends changes, you invoke invalidateIntrinsicContentSize. For example, a text field calls invalidateIntrinsicContentSize if the string value changes.
Layout Operates on Alignment Rectangles, Not Frames
When considering layout, keep in mind that the frame of a control is less important than its visual extent. As a result, ornaments like shadows and engraving lines should typically be ignored for the purposes of layout. Interface Builder has always done this.
In the following example, the Aqua guide (the dashed blue line) aligns with the visual extent of the button, not with the button’s frame (the solid blue rectangle).

To allow layout based on the presentation of the content rather than the frame, views provide an alignment rect, which is what the layout actually operates on. To determine whether your override is correct, you can set the NSViewShowAlignmentRects default to YES to draw the alignment rects.
Views Indicate Baseline Offsets
Frequently you want to align controls by baseline. Although you have always been able to do this in Interface Builder, it was not previously possible to do this at runtime. You can do so now using NSLayoutAttributeBaseline in a constraint.
The method baselineOffsetFromBottom returns the distance between NSLayoutAttributeBottom and NSLayoutAttributeBaseline. This default return value for NSView is 0; the method is overridden by subclasses for which it makes sense to do so.
© 2012 Apple Inc. All Rights Reserved. (Last updated: 2012-09-19)