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.

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:

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

image: ../Art/buttonGuideFrame.png

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.


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