Sie sind auf Seite 1von 30

Cocoa Auto Layout Guide

Contents

About Cocoa Auto Layout 4


At a Glance 4

Constraints Express Relationships Between Views 7


About Constraints 7 Constraints Can Be Inequalities 7 Constraints Have a Priority Level 8 Constraints May Cross View Hierarchies 8 Create Constraints Programmatically Using an ASCII-Art Format String 9 Constraints are Mostly Immutable 10 Install Constraints 10 Auto Layout Degrades Gracefully with Unsatisfiable Constraints 11

Visual Format Language 13


Visual Format Syntax 13 Visual Format String Grammar 14

Dividing Responsibility Between Controllers and Views 17


A View Specifies its Intrinsic Content Size 17 A Controller Specifies How Important the Intrinsic Size Is 18 Views Must Tell the Auto Layout System if Their Intrinsic Size Changes 18 Layout Operates on Alignment Rectangles, Not Frames 18 Views Indicate Baseline Offsets 19

Debugging 20
Debugging Workflow 20 Handling Ambiguity 22

Core Layout Runtime 24 Adopting Auto Layout 27 Document Revision History 29

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

Figures

Debugging 20
Figure 4-1 Figure 4-2 Constraint debugging window illustrating ambiguity 22 Constraint debugging window illustrating alternate resolution of ambiguity 23

Adopting Auto Layout 27


Figure 6-1 Button layout using springs and struts 27

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

About Cocoa Auto Layout

You use the Cocoa Auto Layout system to define layout constraints for user interface elements. Constraints represent relationships between user interface elements such as these views line up head to tail, or this button should move with this split view subview. When laying out the user interface, a constraint satisfaction system arranges the elements in a way that most closely meets the constraints. Important: This document has not been revised to specifically describe the auto layout behavior on iOS. It is included in the iOS Library because the underlying layout concepts are the same between OS X and iOS.

At a Glance
Cocoa Auto Layout lets you define rules for the layout of elements in your user interface. For example, you might want to specify that a text label should be anchored the appropriate distance (as defined by Aqua guidelines) from the sides of its window and an adjacent text field, and that the label should occupy just as much area as required by the string. Such a scenario is illustrated in the window on the left in the following diagram.

Cocoa Auto Layout allows individual views to declare their own preferred size, which means you dont have to specify new layout if the labels text changesfor example, because of localization, as illustrated in the right window. You dont even have to specify new layout for languages like Hebrew and Arabic in which the left to right ordering of elements themselves should generally be reversed.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

About Cocoa Auto Layout At a Glance

Cocoa Auto Layout thus improves the traditional division of responsibility between controllers and views. Rather than you writing a monolithic, omniscient controller that calculates where views need to go for a given geometry, views use constraints to declare where they want to be. Constraints represent relationships between user interface elements such as these views line up head to tail, or this button should move with this split view subview. Constraints themselves are objectsinstances of NSLayoutConstraintthat you install on views. For more about how you architect your application to use the Auto Layout system, see Dividing Responsibility Between Controllers and Views (page 17). Typically, you specify the constraints in Interface Builder. Suppose you drag a text field out of the library, snap it into the bottom left corner of a window, then drag-resize the right edge until it snaps into the bottom right corner. Nothing further is needed to specify that when the window is resized the text field should stretch horizontally. If you need to create constraints programmatically, you typically do so using an ASCII-art inspired format string. For example, you could create a constraint to keep two buttons the standard Aqua spacing apart using a format string like this: [button1]-[button2]. For more about constraints and how to create and use them, see Constraints Express Relationships Between Views (page 7). Cocoa Auto Layout offers several features that can help you find problems if your views are not positioned as you expected. In particular, Auto Layout provides a runtime visualization. For more about diagnosing problems with constraints, see Debugging (page 20). To determine the position of views, Auto Layout adds two passes to the process of rendering a window (in addition to the display pass Cocoa had previously used). In some situations, you may take advantage of these passes to perform custom layout of your own or to force re-layout of the user interface. For more about the the Auto Layout engine, see Core Layout Runtime (page 24). The design of the Auto Layout architecture makes it fairly straightforward to incrementally move a project that uses the springs and struts model for user interface layout to use the Auto Layout system. By default the Auto Layout system translates old-style autosizing masks into constraints to provide compatibility. For more about converting an existing project, see Adopting Auto Layout (page 27). There are several code examples that illustrate how you can use the Auto Layout systemsee Cocoa Autolayout Demos . The following WWDC videos provide another introduction to auto layout as well as example layouts:

WWDC 2012: Introduction to Auto Layout for iOS and OS X WWDC 2012: Auto Layout by Example

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

About Cocoa Auto Layout At a Glance

WWDC 2012: Best Practices for Mastering Auto Layout

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

Constraints Express Relationships Between Views

Constraints represent relationships between user interface elements such as these views line up head to tail, or this button should move with this split view subview.

About Constraints
A constraint is basically a statement of the form y = m*x + b where

y and x are attributes of views.

An attribute is one of left, right, top, bottom, leading, trailing, width, height, centerX, centerY, and baseline. The attributes leading and trailing are the same as left and right in English, but the UI flips in a right-to-left environment like Hebrew or Arabic. When you create constraints using Interface Builder or the visual format strings (see Create Constraints Programmatically Using an ASCII-Art Format String (page 9)), leading and trailing are the default values.
m and b are floating point values.

The following (presented as pseudocode) represents a concrete example of a constraint:


button1.right == button2.left - 12.0

Constraints are not directional, and there are no restrictions on cycles. Layout itself is neither top down nor bottom up. Instead, all constraints are considered at the same time, and elements laid out in such a way that best satisfies all of the constraints.

Constraints Can Be Inequalities


The relation in a constraint does not have to be ==; it can also be <= or >=. For example:
button1.width >= 100.0

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

Constraints Express Relationships Between Views About Constraints

Constraints Have a Priority Level


Constraints have a priority level. A priority level is a floating point value. Constraints with higher priority levels are satisfied before constraints with lower priority levels. The default priority level is NSLayoutPriorityRequired, which means that the constraint must be satisfied exactly. The layout system gets as close as it can to satisfying an optional constraint, even if it cannot completely achieve it. If a constraint a == b is optional, it means that abs(a - b) should be minimized. Priority levels allow you to express useful conditional behavior. For example, they are used to express that all controls should always be sized to fit their contents, unless something more important prevents it. For more detail on this example, see A View Specifies its Intrinsic Content Size (page 17).

Constraints May Cross View Hierarchies


Constraints can, with some restrictions, cross the view hierarchy. In Mail, for example, by default the Delete button in the toolbar lines up with the message table. In Desktop Preferences, the checkboxes at the bottom of the window align with the split view pane they operate on.

It is not legal for a constraint to cross through a view that is manually laid out, or through a view that has a bounds transform (such as a scroll view)you can think of such views as barriers. Theres an inside world and an outside world, but the inside cannot be connected to the outside by constraints.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

Constraints Express Relationships Between Views Create Constraints Programmatically Using an ASCII-Art Format String

Create Constraints Programmatically Using an ASCII-Art Format String


You represent constraints using instances of NSLayoutConstraint. To create constraints, you typically use constraintsWithVisualFormat:options:metrics:views:. The first argument is an ASCII-artinspired visual format string that provides a visual representation of the layout you want to describe. A view is in represented in square brackets, and a connection between views is represented using a hyphen (or two hyphens separated by a number to represent the number of points apart the views should be). Examples and a grammar for the visual format language are given in Visual Format Language (page 13). For example, for this layout

you might represent the relationship between button1 and button2 as


[button1]-12-[button2]

A single hyphen denotes the standard Aqua space, so you could represent the relationship with just
[button1]-[button2]

You pass the visual format string as the first argument to


constraintsWithVisualFormat:options:metrics:views:. The views come from the views

dictionarythe keys are the names you use in the format string, the values are the corresponding views. As a convenience, NSDictionaryOfVariableBindings creates a dictionary where the keys are the same as the corresponding values variable name. The code to create the constraints thus becomes:
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(button1, button2); NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"[button1]-[button2]" options:0 metrics:nil views:viewsDictionary];

The visual format language prefers good visualization over completeness of expressibility; there are therefore constraints that cannot be expressed in visual format syntax, although most of the constraints that are useful in real user interfaces can be. One useful constraint that cannot be expressed is a fixed aspect ratio (for example,

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

Constraints Express Relationships Between Views Constraints are Mostly Immutable

imageView.width = 2 * imageView.height). To create such a constraint, you must use constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:. As an

example, you could create the [button1]-[button2] constraint using the following code.
[NSLayoutConstraint constraintWithItem:button1 attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:button2 attribute:NSLayoutAttributeLeft multiplier:1.0 constant:-12.0];

Constraints are Mostly Immutable


You cannot change most of the properties of a constraint after you create it, but you can still change the constant. There are two reasons for this:

Its algorithmically important. It is much more efficient to change the constant than to remove a constraint and add a new one. It leads to a natural way to implement operations such as dragging, which is exactly the case in which performance is most important.

Install Constraints
To make a constraint active, you must add it to a view. The view that holds the constraint must be an ancestor of the views the constraint involves, often the closest common ancestor. (This is in the existing NSView API sense of the word ancestor , where a view is an ancestor of itself.) The constraint is interpreted in the coordinate system of that view. Suppose you install [zoomableView1]-80-[zoomableView2] on the common ancestor of zoomableView1 and zoomableView2.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

10

Constraints Express Relationships Between Views Auto Layout Degrades Gracefully with Unsatisfiable Constraints

The 80 is in the coordinate system of the container, which is what it looks like if you draw the constraint. If the bounds transform of either of the zoomable views changes, the space between them remains fixed.

If the bounds transform in the container itself is changed, then the space scales too.

NSView provides a methodaddConstraint:to add a constraint, and methods to remove or inspect

existing constraintsremoveConstraint: and constraintsas well as other related methods. NSView also provides a method, fittingSize, which is similar to the sizeToFit method of NSControl but for arbitrary views rather than for controls. The fittingSize method returns the ideal size for the view considering only those constraints installed on the receivers subtree together with a preference for the view to be as small as possible . The fitting size is not the best size for a view in a general sensein the constraint-based system, a views best size if you consider everything has to be the size it currently has!

Auto Layout Degrades Gracefully with Unsatisfiable Constraints


It is a programming error to configure constraints that cannot be satisfied. Faced with unsatisfiable constraints, however, the Auto Layout system attempts to degrade gracefully.
1.

The addConstraint: method (or the setConstant: method of NSLayoutConstraint) logs the mutually unsatisfiable constraints and throws an exception. The exception is appropriate because this is a programmer error.

2.

The system catches the exception immediately. Although adding a constraint that cannot be satisfied is a programmer error, its one that can readily imagine occurring on a users computer, and one from which the system can recover more gracefully than crashing the program. The exception is thrown so that you notice the problem, and caught because its easier to debug the constraint system if the system does still function.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

11

Constraints Express Relationships Between Views Auto Layout Degrades Gracefully with Unsatisfiable Constraints

3.

To allow layout to proceed, the system selects a constraint from among the mutually unsatisfiable set and lowers its priority from required to an internal value that is not required, but is higher priority than anything you can externally specify. The effect is that as things change going forward, this incorrectly broken constraint is the first that the system attempts to satisfy. (Note: every constraint in the set will be required to begin with, because otherwise it wouldnt be causing a problem.)

2010-08-30 03:48:18.589 ak_runner[22206:110b] Unable to simultaneously satisfy constraints: ( "<NSLayoutConstraint: 0x40082d820 H:[NSButton:0x4004ea720'OK']-(20)-| '|':NSView:0x4004ea9a0 ) >", "<NSLayoutConstraint: 0x400821b40 H:[NSButton:0x4004ea720'OK']-(29)-| '|':NSView:0x4004ea9a0 ) >" ) (Names: (Names:

Will attempt to recover by breaking constraint <NSLayoutConstraint: 0x40082d820 H:[NSButton:0x4004ea720'OK']-(20)-| '|':NSView:0x4004ea9a0 ) > (Names:

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

12

Visual Format Language

Visual Format Syntax


The following are examples of constraints you can specify using the visual format. Note how the text visually matches the image. Standard Space
[button]-[textField]

Width Constraint
[button(>=50)]

Connection to Superview
|-50-[orchidBox]-50-|

Vertical Layout
V:[topField]-10-[bottomField]

Flush Views
[maroonView][oceanView]

Priority
[button(100@20)]

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

13

Visual Format Language Visual Format String Grammar

Equal Widths
[button1(==button2)]

Multiple Predicates
[flexibleButton(>=70,<=100)]

A Complete Line of Layout


|-[find]-[findNext]-[findField(>=20)]-|

The notation prefers good visualization over completeness of expressibility. There are constraints that cannot be expressed in visual format syntax, although most of the constraints that are useful in real user interfaces can be. One useful constraint that cannot be expressed is a fixed aspect ratio (for example, imageView.width = 2 * imageView.height). To create such a constraint, you must use constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant:.

Visual Format String Grammar


The visual format string grammar is defined as follows (literals are shown in code font; e denotes the empty string).
Symbol Replacement rule

<visualFormatString>

(<orientation>:)? (<superview><connection>)? <view>(<connection><view>)* (<connection><superview>)?

<orientation> <superview>

H|V |

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

14

Visual Format Language Visual Format String Grammar

Symbol

Replacement rule [<viewName>(<predicateListWithParens>)?]

<view> <connection> <predicateList> <simplePredicate> <predicateListWithParens> <predicate> <relation> <objectOfPredicate> <priority> <constant> <viewName>

e|-<predicateList>-|<simplePredicate>|<predicateListWithParens> <metricName>|<positiveNumber>
(<predicate>(,<predicate>)*)

(<relation>)?(<objectOfPredicate>)(@<priority>)?
==|<=|>=

<constant>|<viewName> (see note) <metricName>|<number> <metricName>|<number> Parsed as a C identifier. This must be a key mapping to an instance of NSView in the passed views dictionary.

<metricName>

Parsed as a C identifier. This must be a key mapping to an instance of NSNumber in the passed metrics dictionary. As parsed by strtod_l, with the C locale.

<number>

Note: For the objectOfPredicate production, a viewName is only acceptable if the subject of the predicate is the width or height of a view. That is, you can use [view1(==view2)] to specify that view1 and view2 have the same width.

If you make a syntactic mistake, an exception is thrown with a diagnostic message. For example:
Expected ':' after 'V' to specify vertical arrangement V|[backgroundBox]| ^

A predicate on a view's thickness must end with ')' and the view must end with ']' |[whiteBox1][blackBox4(blackWidth][redBox]|

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

15

Visual Format Language Visual Format String Grammar

Unable to find view with name blackBox |[whiteBox2][blackBox] ^

Unknown relation. Must be ==, >=, or <= V:|[blackBox4(>30)]| ^

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

16

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 buttons intrinsicContentSize method 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 widththe slider artwork has no intrinsic best width. A horizontal NSSlider object 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.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

17

Dividing Responsibility Between Controllers and Views A Controller Specifies How Important the Intrinsic Size Is

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.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

18

Dividing Responsibility Between Controllers and Views Views Indicate Baseline Offsets

In the following example, the Aqua guide (the dashed blue line) aligns with the visual extent of the button, not with the buttons 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-09-19 | 2012 Apple Inc. All Rights Reserved.

19

Debugging

In an constraint-based layout system, the ability to debug effectively is clearly very important. Cocoa Auto Layout offers several features to help you find the source of errors.

An exception is thrown if you configure constraints that cannot be satisfied. See Auto Layout Degrades Gracefully with Unsatisfiable Constraints (page 11).

Auto Layout provides runtime support for visualizing constraints. Visualization may be useful both for finding a problematic constraint, and for detecting ambiguous constraints.

You can programmatically query the system to ask about ambiguous constraints. You can send a view a hasAmbiguousLayout message to determine whether its frame is ambiguous, and visualize the ambiguity using exerciseAmbiguityInLayout (see Handling Ambiguity (page 22)).

An instrument in Instruments helps you to understand changes over time. The Auto Layout instrument may be included with the developer tools in the future, but is currently provided as sample code in a templatesee Cocoa Autolayout Demos .

Debugging Workflow
Broadly speaking, there are two phases to debugging a layout problem:
1. 2.

Map from this view is in the wrong place to this constraint (or these constraints) is (are) incorrect. Map from this constraint is incorrect to this code is incorrect.

To debug a problem with Auto Layout


1.

Identify the view with an incorrect frame. It may be obvious which view has the problem; if it is not, you may find it helpful to use the NSView method _subtreeDescription to create a textual description of the view hierarchy. (The _subtreeDescription method is not public API; it is, however, permissible to use for debugging purposes.)

2.

If possible, reproduce the issue while running under the Auto Layout template in Instruments.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

20

Debugging Debugging Workflow

(The Auto Layout instrument may be included with the developer tools in the future, but is currently provided as sample code in a templatesee Cocoa Autolayout Demos ).
3.

Find the bad constraint or constraints. To get the constraints affecting a particular view, use
constraintsAffectingLayoutForOrientation:. You can then inspect the constraints in the

debugger. They are printed using the visual format notation. If your views have identifiers (see identifier (NSView)), they print out using the identifier in the description, like this:
<NSLayoutConstraint: 0x400bef8e0 H:[refreshSegmentedControl]-(8)-[selectViewSegmentedControl] (Names: refreshSegmentedControl:0x40048a600, selectViewSegmentedControl:0x400487cc0 ) >

otherwise the output looks like this:


<NSLayoutConstraint: 0x400cbf1c0 H:[NSSegmentedControl:0x40048a600]-(8)-[NSSegmentedControl:0x400487cc0]>

4.

If its not obvious which constraint is wrong at this point, visualize the constraints on screen by passing the constraints to the window using visualizeConstraints:. Heres an example of visualizing the constraints affecting the find fields horizontal layout:

When you click a constraint, it is printed in the console. In this way you can you can determine which is which, and typically identify which is incorrect. At this point you may be informed that the layout is ambiguous (see Handling Ambiguity (page 22)).
5.

Find the code thats wrong. Sometimes, once you have identified the incorrect constraint, you will know what to do to fix it.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

21

Debugging Handling Ambiguity

If this is not the case then, in Instruments, search for the pointer of the constraint (or some of its description). This will show you interesting events in that constraints lifecycleits creation, modification, installation into windows, and so on. For each of these you can see the backtrace where it happened. Find the stage at which things went awry, and look at the backtrace. This is the code with the problem.

Handling Ambiguity
In the above workflow, we assumed that the issue was an incorrect constraint. It is also possible that the problem is due to a missing constraint. A layout is ambiguous if it is underspecified. For example, suppose the system consists of one constraint.
x + y == 100

Because there are an infinite number of solutions to this equation, the system is ambiguous (as opposed to unsatisfiable). You can resolve it by adding a second constraint such as:
x == y

In the normal course of solving layout, the system detects unsatisfiability but not ambiguity. (It is a computationally expensive task to detect ambiguity in this system.) However, if you visualize constraints the system does check for ambiguity. If it detects an ambiguity, the visualizer presents an Exercise Ambiguity button. Figure 4-1 (page 22) shows the find panel after one of the constraints has been removed.
Figure 4-1 Constraint debugging window illustrating ambiguity

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

22

Debugging Handling Ambiguity

Exercising ambiguity (clicking the button) makes your UI toggle between different states it could be in given the current set of constraints. Figure 4-2 (page 23) shows the layout of the find panel after clicking Exercise Ambiguity. Notice the different layout.
Figure 4-2 Constraint debugging window illustrating alternate resolution of ambiguity

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

23

Core Layout Runtime

In addition to the display pass Cocoa has always used, Cocoa Auto Layout adds two more passes that occur when rendering a window: updateConstraintsIfNeeded and layoutIfNeeded. These occur in order: update constraints, layout, display. If you invoke display manually, it invokes layout and layout invokes updateConstraints. You can think of the update constraints pass as a measurement pass that communicates changes in geometry to the layout system. For example, if you change the title of a button at some point the text has to be measured, and a constraint has to be set up that communicates that information into the layout system. The update constraints pass is bottom-up. It is in the layout pass that the frames of views are updated. The layout pass is top-down. These passes have parallel sets of methods:
Display Layout Update Constraints Override

I D

Perform pass at window level

displayIfNeeded

layoutIfNeeded

(NSWindow)

(NSWindow)

updateConstraintsIfNeeded

No.

(NSWindow)

N c a b b c n t u r

Perform pass at view level Sets things up and invokes the view overridable method on all views in subtree that are dirty with respect to the pass.

displayIfNeeded

(NSView)

layoutSubtreeIfNeeded

updateConstraintsForSubtreeIfNeeded

No.

(NSView)

(NSView)

N c a b b c n t u r

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

24

Core Layout Runtime

Display

Layout

Update Constraints

Override

I D

View level overridable method Subclassers should override this method to do the requested work for the receiver. This implementation should not dirty the current or previous passes or invoke later passes. Invalidation Get / set methods for invalidation of the pass.

drawRect:

layout

updateConstraints

Yes.

(NSView)

(NSView)

(NSView)

Y n m d

needsDisplay (NSView) setNeedsDisplay: (NSView)

needsLayout (NSView) setNeedsLayout: (NSView)

needsUpdateConstraints

No.

Y n

(NSView)
setNeedsUpdateConstraints:

(NSView) If youre implementing a custom view, the most common methods to interact with are the view-level overridable methods and the invalidation methods.

You can override updateConstraints to perform deferred constraint setup. You invoke setNeedsUpdateConstraints: when you have set up you want to defer. This is particularly useful when a nib file is loaded and properties are changing a lotyou wont receive updateConstraints until things have settled down. You should only override layout only if you want to do custom layout. If you do, then you also need to invoke setNeedsLayout: when something that feeds into your custom layout changes.

To reiterate: you never need to call setNeedsLayout: unless you override layout. Based on changes to constraints, the layout engine determines when layout is required. A controller object is typically more concerned with the NSWindow and NSView methods that perform the pass. These uses are more rare, though still valid and needed on occasion.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

25

Core Layout Runtime

Perform the update constraints pass manually to make sure all constraints are up to date. You might do this before introspecting a constraint to extract a metric.

Perform the layout pass manually if you want to extract frames from views and make decisions based on them. If you dont make sure layout is up to date first, the frames wont be meaningful. An NSAlert object uses this as part of its layout. The constraint-based system doesnt deal with flowed text and line breaking any better (or worse) than springs and struts does. NSAlert sets up all its constraints except for anything giving the height of the text fields. Then it calls layoutSubtreeIfNeeded. At this point the text fields have the correct width but not the correct height. It then uses NSTextField methods to find the appropriate height for the fields given their width, and adds the height constraints.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

26

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 views 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 superviews 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

views 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

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

27

Adopting Auto Layout

NSSplitView, an NSTabViewItems 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 dont 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 youre 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.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

28

Document Revision History

This table describes the changes to Cocoa Auto Layout Guide .

Date 2012-09-19 2012-02-16 2011-07-06

Notes Added to iOS Library. Added links to WWDC videos. Corrected minor code error. New document that describes the constraint-based system for laying out user interface elements.

2012-09-19 | 2012 Apple Inc. All Rights Reserved.

29

Apple Inc. 2012 Apple Inc. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, mechanical, electronic, photocopying, recording, or otherwise, without prior written permission of Apple Inc., with the following exceptions: Any person is hereby authorized to store documentation on a single computer for personal use only and to print copies of documentation for personal use provided that the documentation contains Apples copyright notice. No licenses, express or implied, are granted with respect to any of the technology described in this document. Apple retains all intellectual property rights associated with the technology described in this document. This document is intended to assist application developers to develop applications only for Apple-labeled computers. Apple Inc. 1 Infinite Loop Cupertino, CA 95014 408-996-1010 Apple, the Apple logo, Aqua, Cocoa, Finder, Instruments, and OS X are trademarks of Apple Inc., registered in the U.S. and other countries. iOS is a trademark or registered trademark of Cisco in the U.S. and other countries and is used under license.
Even though Apple has reviewed this document, APPLE MAKES NO WARRANTY OR REPRESENTATION, EITHER EXPRESS OR IMPLIED, WITH RESPECT TO THIS DOCUMENT, ITS QUALITY, ACCURACY, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. AS A RESULT, THIS DOCUMENT IS PROVIDED AS IS, AND YOU, THE READER, ARE ASSUMING THE ENTIRE RISK AS TO ITS QUALITY AND ACCURACY. IN NO EVENT WILL APPLE BE LIABLE FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES RESULTING FROM ANY DEFECT OR INACCURACY IN THIS DOCUMENT, even if advised of the possibility of such damages. THE WARRANTY AND REMEDIES SET FORTH ABOVE ARE EXCLUSIVE AND IN LIEU OF ALL OTHERS, ORAL OR WRITTEN, EXPRESS OR IMPLIED. No Apple dealer, agent, or employee is authorized to make any modification, extension, or addition to this warranty. Some states do not allow the exclusion or limitation of implied warranties or liability for incidental or consequential damages, so the above limitation or exclusion may not apply to you. This warranty gives you specific legal rights, and you may also have other rights which vary from state to state.

Das könnte Ihnen auch gefallen