Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

Auto Layouters Anonymous The 1st annual CocoaHeadsNL meeting of the Thomas Visser, @thomvis88 ALA

Slide 3

Slide 3 text

“I have never tried Auto Layout”

Slide 4

Slide 4 text

“I have no idea what Auto Layout is”

Slide 5

Slide 5 text

“I tried using Auto Layout and hated it”

Slide 6

Slide 6 text

“I tried using Auto Layout, hated it, tried it again and now love it.”

Slide 7

Slide 7 text

“I tried using Auto Layout, hated it, tried it again, loved it, used it for absolutely everything, that didn’t work out too well and now I try to use it where it makes sense.”

Slide 8

Slide 8 text

Technology Trigger http://www.gartner.com/technology/research/methodologies/hype-cycle.jsp Peak of Inflated Expectations Through of Disillusionment Slope of Enlightenment Plateau of Productivity Me

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Springs & Struts (0,0) 133 100

Slide 11

Slide 11 text

Springs & Struts

Slide 12

Slide 12 text

Auto Layout >= 0 >= 0 == 8 == 8

Slide 13

Slide 13 text

Past Springs & Struts

Slide 14

Slide 14 text

Auto Layout Future

Slide 15

Slide 15 text

Auto Layout • Uniform layout description for multiple orientations & UI idioms • Declarative UI definition • More flexible UI for easier localisation • Bi-directional UI support • Fun

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

_horizontalSpacingConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_checkboxView]-(checkboxToLabelSpacing)-[_labelView]-|" options:0 metrics:@{@"checkboxToLabelSpacing": @(kHSCheckboxToLabelHorizontalSpacing)} views:views]; [self addConstraints: _horizontalSpacingConstraints]; _checkboxVerticalCenteringConstraint = [NSLayoutConstraint constraintWithItem:_checkboxView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]; [self addConstraint: _checkboxVerticalCenteringConstraint]; _labelVerticalCenteringConstraint = [NSLayoutConstraint constraintWithItem:_labelView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]; [self addConstraint: _labelVerticalCenteringConstraint]; ! _checkboxWidthConstraint = [NSLayoutConstraint constraintWithItem:_checkboxView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:kHSCheckboxSize.width]; _checkboxWidthConstraint.priority = UILayoutPriorityRequired; [_checkboxView addConstraint: _checkboxWidthConstraint]; _checkboxHeightConstraint = [NSLayoutConstraint constraintWithItem:_checkboxView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0 constant:kHSCheckboxSize.height]; _checkboxHeightConstraint.priority = UILayoutPriorityRequired; [_checkboxView addConstraint: _checkboxHeightConstraint]; _checkboxHeightToContentHeightConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-(verticalPadding)-[_checkboxView]-(verticalPadding)-|" options:0 metrics:@{@"verticalPadding": @(kHSCheckboxVerticalPadding)}

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

Xcode 4

Slide 24

Slide 24 text

Xcode 5

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

A Constraint Defines a relation between two view attributes

Slide 27

Slide 27 text

A Constraint view.left = superview.left + 100.0 100 Defines a relation between two view attributes

Slide 28

Slide 28 text

A Constraint view.trailing <= superview.trailing - 200 <= -200 Defines a relation between two view attributes

Slide 29

Slide 29 text

A Constraint Defines a relation between two view attributes view.trailing <= superview.trailing - 200 <= -200

Slide 30

Slide 30 text

view.centerY = superview.centerY * 0.5 A Constraint centerY 0.5* centerY centerY Defines a relation between two view attributes

Slide 31

Slide 31 text

view.width = superview.width * 0.5 A Constraint 1:2 Defines a relation between two view attributes

Slide 32

Slide 32 text

A Constraint view1.attribute1 = view2.attribute2 * multiplier + constant

Slide 33

Slide 33 text

view1.attribute1 = view2.attribute2 * multiplier + constant A Constraint

Slide 34

Slide 34 text

view1.attribute1 = view2.attribute2 * multiplier + constant A Constraint typedef NS_ENUM(NSInteger, NSLayoutAttribute) { NSLayoutAttributeLeft = 1, NSLayoutAttributeRight, NSLayoutAttributeTop, NSLayoutAttributeBottom, NSLayoutAttributeLeading, NSLayoutAttributeTrailing, NSLayoutAttributeWidth, NSLayoutAttributeHeight, NSLayoutAttributeCenterX, NSLayoutAttributeCenterY, NSLayoutAttributeBaseline, NSLayoutAttributeNotAnAttribute = 0 };

Slide 35

Slide 35 text

A Constraint typedef NS_ENUM(NSInteger, NSLayoutRelation) { NSLayoutRelationLessThanOrEqual = -1, NSLayoutRelationEqual = 0, NSLayoutRelationGreaterThanOrEqual = 1, }; view1.attribute1 = view2.attribute2 * multiplier + constant

Slide 36

Slide 36 text

A Constraint enum { UILayoutPriorityRequired = 1000, UILayoutPriorityDefaultHigh = 750, UILayoutPriorityDefaultLow = 250, UILayoutPriorityFittingSizeLevel = 50, }; typedef float UILayoutPriority; @ priority view1.attribute1 = view2.attribute2 * multiplier + constant

Slide 37

Slide 37 text

A Constraint goes both ways @ priority view1.attribute1 = view2.attribute2 * multiplier + constant

Slide 38

Slide 38 text

A Constraint @ priority view1.attribute1 = view2.attribute2 * multiplier + constant view.width = superview.width * 0.5 + 0.0 1:2 goes both ways

Slide 39

Slide 39 text

view.width = superview.width * 0.5 + 0.0 A Constraint @ priority view1.attribute1 = view2.attribute2 * multiplier + constant goes both ways

Slide 40

Slide 40 text

view.width = superview.width * 0.5 + 0.0 A Constraint superview.width = (view.width - 0.0)/0.5 @ priority view1.attribute1 = view2.attribute2 * multiplier + constant goes both ways

Slide 41

Slide 41 text

Intrinsic Content Size

Slide 42

Slide 42 text

Intrinsic Content Size Content hugging priority < external width constraint

Slide 43

Slide 43 text

Intrinsic Content Size Content compression resistance priority < external width constraint

Slide 44

Slide 44 text

Layout Engine • Constraints • Intrinsic Content Sizes Meet as many constraints and intrinsic content sizes as possible, keeping constraint priority, content hugging and compression resistance into account Inputs Process

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

Meet as many constraints and intrinsic content sizes as possible, keeping constraint priority, content hugging and compression resistance into account Layout Engine • Constraints • Intrinsic Content Sizes Inputs Process

Slide 47

Slide 47 text

Layout Engine • Constraints • Intrinsic Content Sizes Linear Algebra Inputs Process

Slide 48

Slide 48 text

Layout Engine Inputs • Constraints • Intrinsic Content Sizes Process Linear Algebra Output • No layout
 or • Multiple Layouts
 or • A Single Layout

Slide 49

Slide 49 text

Layout Engine Unsatisfiable constraints Ambiguous layout • Constraints • Intrinsic Content Sizes Linear Algebra ✔ Inputs Process Output • No layout
 or • Multiple Layouts
 or • A Single Layout

Slide 50

Slide 50 text

A Fully Specified Layout • At least two constraints or content size specification per axis ! • No contradicting constraints ! • Result: Every view has a valid frame

Slide 51

Slide 51 text

No content

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

_horizontalSpacingConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_checkboxView]-(checkboxToLabelSpacing)-[_labelView]-|" options:0 metrics:@{ @"checkboxToLabelSpacing": @(kHSCheckboxToLabelHorizontalSpacing) } views:views]; [self addConstraints: _horizontalSpacingConstraints]; H:|[_checkboxView]-(checkboxToLabelSpacing)-[_labelView]-|

Slide 54

Slide 54 text

H:|[_checkboxView]-(checkboxToLabelSpacing)-[_labelView]-|

Slide 55

Slide 55 text

_horizontalSpacingConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_checkboxView]-(checkboxToLabelSpacing)-[_labelView]-|" options:0 metrics:@{ @"checkboxToLabelSpacing": @(kHSCheckboxToLabelHorizontalSpacing) } views:views]; [self addConstraints: _horizontalSpacingConstraints]; H:|[_checkboxView]-(checkboxToLabelSpacing)-[_labelView]-|

Slide 56

Slide 56 text

_labelVerticalCenteringConstraint = [NSLayoutConstraint constraintWithItem:_labelView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]; [self addConstraint: _labelVerticalCenteringConstraint];

Slide 57

Slide 57 text

Interface Builder Visual Format constraintWithItem: Ease of Use +++ ++ + Expressiveness + + +++

Slide 58

Slide 58 text

Animations • Frame changes can be animated. • Frames change by changing constraints. • Constraint changes can be animated.

Slide 59

Slide 59 text

Animations • Frame changes can be animated. • Frames change by changing constraints. • Constraint changes can be animated. UIView

Slide 60

Slide 60 text

[UIView animateWithDuration:0.3 animations:^{ _leftView.frame = CGRectMake(10, 10, 20, 20); }];

Slide 61

Slide 61 text

constraint.constant = 65; ! [UIView animateWithDuration:0.3 animations:^{ [_leftView layoutIfNeeded]; } completion:nil];

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

constraint.constant = 65; ! [UIView animateWithDuration:0.3 animations:^{ [_leftView layoutIfNeeded]; } completion:nil];

Slide 64

Slide 64 text

No content

Slide 65

Slide 65 text

- (void)pan:(UIPanGestureRecognizer*)sender { if (sender.state == UIGestureRecognizerStateBegan) { ! _grabbedView = [self.view hitTest:[sender locationInView:self.view] withEvent:nil]; ! } else if (sender.state == UIGestureRecognizerStateChanged) { ! CGPoint trans = [sender translationInView: self.view]; _grabbedView.center = CGPointMake(_grabbedView.center.x+trans.x, _grabbedView.center.y+trans.y); [sender setTranslation:CGPointZero inView:self.view]; } else if (sender.state == UIGestureRecognizerStateEnded) { ! [_grabbedView setNeedsLayout]; [UIView animateWithDuration:1.0 animations:^{ [_grabbedView layoutIfNeeded]; }]; ! } }

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

Animation Caveats • Scope of [view layoutIfNeeded] is fuzzy • Anchor point determined by Auto Layout (CGAffineTransformScale )

Slide 68

Slide 68 text

Animation Caveats • “Auto Layout is animating changes that I don’t want to animate!?” • “Auto Layout is not animating changes that I do want to animate!?”

Slide 69

Slide 69 text

Animation Caveats >= 20 >= 20

Slide 70

Slide 70 text

Animation Caveats >= 20 >= 20

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

>= 0 @ 1000 >= 0 @ 1000

Slide 74

Slide 74 text

>= 0 @ 1000 >= 0 @ 1000 >= 0 @ 1000

Slide 75

Slide 75 text

>= 0 @ 1000 >= 0 @ 1000 >= 0 @ 1000 ! ! @ 500 @ 500

Slide 76

Slide 76 text

No content

Slide 77

Slide 77 text

Final Notes

Slide 78

Slide 78 text

UIScrollView & Auto Layout is tricky 
 http://developer.apple.com/library/ios/technotes/tn2154/_index.html

Slide 79

Slide 79 text

UIScrollView & Auto Layout is tricky 
 http://developer.apple.com/library/ios/technotes/tn2154/_index.html

Slide 80

Slide 80 text

http://oleb.net/blog/2014/03/how-i-learned-to-stop-worrying-and-love-auto-layout/ Auto Layout is not all or nothing and that’s a good thing

Slide 81

Slide 81 text

Auto Layout is not free (as in no-op) 
 [self.window addConstraints: allMyConstraints]; ❌

Slide 82

Slide 82 text

[self.deepestPossibleView addConstraints: allMyConstraints]; ✔ Auto Layout is not free (as in no-op) 


Slide 83

Slide 83 text

! 
 http://floriankugler.com/blog/2013/4/21/auto-layout-performance-on-ios Auto Layout is not free (as in no-op) 


Slide 84

Slide 84 text

Debugging Auto Layout problems is overwhelming at first

Slide 85

Slide 85 text

Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "", "", "", "", "", "", "", "" ) ! Will attempt to recover by breaking constraint ! Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.

Slide 86

Slide 86 text

// Debugging ! /* Everything in this section should be used in debugging only, never in shipping code. These methods may not exist in the future - no promises. */ @interface UIView (UIConstraintBasedLayoutDebugging) ! /* This returns a list of all the constraints that are affecting the current location of the receiver. The constraints do not necessarily involve the receiver, they may affect the frame indirectly. Pass UILayoutConstraintAxisHorizontal for the constraints affecting [self center].x and CGRectGetWidth([self bounds]), and UILayoutConstraintAxisVertical for the constraints affecting[self center].y and CGRectGetHeight([self bounds]). */ - (NSArray *)constraintsAffectingLayoutForAxis:(UILayoutConstraintAxis)axis NS_AVAILABLE_IOS(6_0); ! /* If there aren't enough constraints in the system to uniquely determine layout, we say the layout is ambiguous. For example, if the only constraint in the system was x = y + 100, then there are lots of different possible values for x and y. This situation is not automatically detected by UIKit, due to performance considerations and details of the algorithm used for layout. The symptom of ambiguity is that views sometimes jump from place to place, or possibly are just in the wrong place. -hasAmbiguousLayout runs a check for whether there is another center and bounds the receiver could have that could also satisfy the constraints. -exerciseAmbiguousLayout does more. It randomly changes the view layout to a different valid layout. Making the UI jump back and forth can be helpful for figuring out where you're missing a constraint. */ - (BOOL)hasAmbiguousLayout NS_AVAILABLE_IOS(6_0); - (void)exerciseAmbiguityInLayout NS_AVAILABLE_IOS(6_0); @end

Slide 87

Slide 87 text

• http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html • https://developer.apple.com/library/ios/documentation/ UserExperience/Conceptual/AutolayoutPG/Introduction/ Introduction.html# Literature

Slide 88

Slide 88 text

Thanks Thomas Visser, @thomvis88 (We’re hiring @touchwonders) www.touchwonders.com