KEMBAR78
Autolayout | PDF
jano@jano.com.es
LayoutAuto
LayoutAuto
Layout
bounds
center }frame
transform
autoresizingMask
Layout
frame.origin = center - (bounds.size / 2.0)
center = frame.origin + (bounds.size / 2.0)
frame.size = bounds.size
bounds
center }frame
transform
autoresizingMask
Layout
frame.origin = center - (bounds.size / 2.0)
center = frame.origin + (bounds.size / 2.0)
frame.size = bounds.size
Layout
AutoLayout
AutoLayout
LayoutAutoLayout
LayoutAutoLayout
descriptive
constraint-based
pixel-perfect
modular
view1.attribute1 RELATION multiplier * view2.attribute2 + constant
button.center.y = 1 * superview.center.y + 0
! [NSLayout
! constrain
! attribute
! relatedBy
! toItem: s
! attribute
! multiplie
! constant:
What do I need to know?
What do I need to know?
UIView properties
alignmentRectInsets
constraints
contentSize
compression
hugging
translatesAutoresizingMaskIntoConstraints
What do I need to know?
UIView properties
Interface Builder > VFL > API
What do I need to know?
UIView properties
Interface Builder > VFL > API
UIViewController lifecycle
What do I need to know?
UIView properties
Interface Builder > VFL > API
Animation
UIView Properties
constraints
Layout
Content
Autosizing
NSLayoutConstraint
NSContentSizeLayoutConstraint
NSAutoresizingMaskLayoutConstraint
constraints
view1.attribute1 RELATION multiplier * view2.attribute2 + constant
NSLayoutAttributeLeft
NSLayoutAttributeRight
NSLayoutAttributeTop
NSLayoutAttributeBottom
NSLayoutAttributeLeading
NSLayoutAttributeTrailing
NSLayoutAttributeWidth
NSLayoutAttributeHeight
NSLayoutAttributeCenterX
NSLayoutAttributeCenterY
NSLayoutAttributeBaseline
NSLayoutAttributeNotAnAttribute
NSLayoutRelationEqual
NSLayoutRelationGreaterThanOrEqual
NSLayoutRelationLessThanOrEqual
constraints
! [NSLayoutConstraint
! constraintWithItem: button
! attribute: NSLayoutAttributeCenterX
! relatedBy: NSLayoutRelationEqual
! toItem: superview
! attribute: NSLayoutAttributeCenterX
! multiplier: 1.0
! constant: 0.0]
constraints
view1.attribute1 RELATION multiplier * view2.attribute2 + constant
! constraint = [NSLayoutConstraint
! constraintWithItem: view
! attribute: NSLayoutAttributeWidth
! relatedBy: NSLayoutRelationEqual
! toItem: nil
! attribute: NSLayoutAttributeNotAnAttribute
! multiplier: 1.0
! constant: 100.0];
[view addConstraint: constraint];
! constraint = [NSLayoutConstraint
! constraintWithItem: view
! attribute: NSLayoutAttributeWidth
! relatedBy: NSLayoutRelationEqual
! toItem: nil
! attribute: NSLayoutAttributeNotAnAttribute
! multiplier: 1.0
! constant: 80.0];
[view addConstraint: constraint];
size=100x80
CONSTRAINT_SIZE(view,100,80);
constraints
view1.attribute1 RELATION multiplier * view2.attribute2 + constant
linear equations
Cassowary Linear Arithmetic
Constraint Solving Algorithm
Pro tip: Use local flat hierarchies.
constraints
view1.attribute1 RELATION multiplier * view2.attribute2 + constant
http://pilky.me/view/36
constraints
view1.attribute1 RELATION multiplier * view2.attribute2 + constant
http://pilky.me/view/36
constraints
Screw-ups
invisible view {
{crash
{undefined
Size not set
Invalid
Ambiguous
Unsatisfiable
Unsatisfiable
Invalid
Ambiguous
view.hasAmbiguousLayout
view.exerciseAmbiguityInLayout
for (UIView *view in self.subviews) {
if ([view hasAmbiguousLayout]){
NSLog(@"<%@:0x%0x>", view.description, (int)self);
}
}
instrinsicContentSize
Suggested size for the view.
- (CGSize) intrinsicContentSize {
return mySize;
}
[self invalidateIntrinsicContentSize];
UIImage *img = UIImage imageNamed:@"Icon.png"];
UIImageView *iv = [[UIImageView alloc] initWithImage:img];
NSLog(@"%@", NSStringFromCGSize(iv.intrinsicContentSize));
Alignment rectangle
UIView
- (UIEdgeInsets)alignmentRectInsets
- (CGRect)frameForAlignmentRect:(CGRect)alignmentRect
- (CGRect)alignmentRectForFrame:(CGRect)frame
Show rect lines:
Hug & compress
Hugging resists stretching
Compression resists shrinking
UILayoutConstraintAxis axis = UILayoutConstraintAxisHorizontal;
UILayoutPriority p = UILayoutPriorityDefaultHigh;
[button setContentCompressionResistancePriority:p forAxis:axis];
[button setContentHuggingPriority:p forAxis:axis];
UIView properties
Interface Builder > VFL > API
Animation
Interface Builder
Interface Builder
Interface Builder
Interface Builder
Interface Builder
Interface Builder
IB > VFL > API
Constraints colors
IB can’t create ambiguous layouts
Add a constraint before deleting another
Preserve intrinsic size
Don’t optimize until everything is in place
UIView properties
Interface Builder > VFL > API
Animation
Visual Format Language
VFL
[NSLayoutConstraint
! constraintsWithVisualFormat:@"H:|-[buttonA]-|"
! options:0
! metrics:nil
! views:@{ @"buttonA" : buttonA }];
VFL
H V [view] | - @ ()
[NSLayoutConstraint
! constraintsWithVisualFormat:@"H:|-[buttonA]-|"
! options:0
! metrics:nil
! views:@{ @"buttonA" : buttonA }];
VFL
[NSLayoutConstraint
! constraintsWithVisualFormat:@"H:|-[buttonA]-|"
! options:0
! metrics:nil
! views:@{ @"buttonA" : buttonA }];
NSLayoutFormatAlignAllLeft
NSLayoutFormatAlignAllRight
NSLayoutFormatAlignAllTop
NSLayoutFormatAlignAllBottom
NSLayoutFormatAlignAllLeading
NSLayoutFormatAlignAllTrailing
NSLayoutFormatAlignAllCenterX
NSLayoutFormatAlignAllCenterY
NSLayoutFormatAlignAllBaseline
NSLayoutFormatAlignmentMask
NSLayoutFormatDirectionLeadingToTrailing
NSLayoutFormatDirectionLeftToRight
NSLayoutFormatDirectionRightToLeft
NSLayoutFormatDirectionMask
NSLayoutFormatOptions
VFL
[NSLayoutConstraint
! constraintsWithVisualFormat:@"H:|-[buttonA]-distance-|"
! options:0
! metrics: @{ @"distance": @50 }
! views:@{ @"buttonA" : buttonA }];
VFL
[NSLayoutConstraint
! constraintsWithVisualFormat:@"H:|-[buttonA]-distance-|"
! options:0
! metrics: @{ @"distance": @50 }
! views:@{ @"buttonA" : buttonA }];
VFL
[NSLayoutConstraint
! constraintsWithVisualFormat:@"H:|-[buttonA]-distance-|"
! options:0
! metrics: @{ @"distance": @50 }
! views:NSDictionaryOfVariableBindings(buttonA)];
VFL
H V [view] | - @ ()
H:[view1][view2]
H:[view1]-[view2]
H:[view1]-30-[view2]
H:[view1]-(==30)-[view2]
H:|[view1]-[view2]|
H:|-[view1]-(>=0)-[view2]-|
H:|-[view1(>=125,<=250)]-(>=0)-[view2]-|
H:[view1(>=view2)][view2]
H:[button(100@20)]
H:|[view1]-(>=50@30)-[view2]|
H:|-[view1(==view2)]-[view2]-|
H:[view1(view2)]
...
100x100 Square
- (void)viewDidLoad
{
[super viewDidLoad];
self.blueView.translatesAutoresizingMaskIntoConstraints = NO;
[self.blueView setContentHuggingPriority:UILayoutPriorityDefaultHigh
forAxis:UILayoutConstraintAxisHorizontal];
[self.blueView setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh
forAxis:UILayoutConstraintAxisVertical];
[self.blueView removeConstraints:self.blueView.constraints];
[self.blueView.superview removeConstraints:self.blueView.superview.constraints];
NSArray *constraints = @[ @"H:[blueView(100)]", @"V:[blueView(100)]"];
NSDictionary *views = @{@"blueView":self.blueView};
for (NSString *format in constraints)
{
[self.view addConstraints:
[NSLayoutConstraint
constraintsWithVisualFormat: format
options: 0
metrics: nil
views: views]];
}
}
UIView properties
Interface Builder > VFL > API
Animation
UIView API
UIView API
Opting in to Constraint-Based Layout
+ requiresConstraintBasedLayout
– translatesAutoresizingMaskIntoConstraints
– setTranslatesAutoresizingMaskIntoConstraints:
Managing Constraints
– constraints
– addConstraint:
– addConstraints:
– removeConstraint:
– removeConstraints:
Measuring in Constraint-Based Layout
– systemLayoutSizeFittingSize
– intrinsicContentSize
– invalidateIntrinsicContentSize
– contentCompressionResistancePriorityForAxis:
– setContentCompressionResistancePriority:forAxis:
– contentHuggingPriorityForAxis:
– setContentHuggingPriority:forAxis:
UIView API
Aligning Views with Constraint-Based Layout
– alignmentRectForFrame:
– frameForAlignmentRect:
– alignmentRectInsets
– viewForBaselineLayout
Triggering Constraint-Based Layout
– needsUpdateConstraints
– setNeedsUpdateConstraints
– updateConstraints
– updateConstraintsIfNeeded
Debugging Constraint-Based Layout
– constraintsAffectingLayoutForAxis:
– hasAmbiguousLayout
– exerciseAmbiguityInLayout
CALayer API
CALayer
– layoutIfNeeded
UIViewController
viewDidLoad
- autolayout-
viewDidLayoutSubviews
viewDidAppear
[self.view layoutIfNeeded]
UIView properties
Interface Builder > VFL > API
Animation
Animation
Animation
#238: Animate the constant
constant
self.someConstraint.constant = 10.0;
[UIView animateWithDuration:0.25 animations:^{
[self.view layoutIfNeeded];
}];
Animation
#238: Animate the constant.
#238: Call layoutIfNeeded in a block.
layoutIfNeeded
- (BOOL)continueTrackingWithTouch:(UITouch *)touch
withEvent:(UIEvent *)event
{
! CGPoint touchPoint = [touch locationInView:self];
! [UIView animateWithDuration:0.1f animations:^(){
! ! NSLayoutConstraint *constraint =
! ! [trackView constraintNamed:THUMB_POSITION_TAG];
! ! constraint.constant = touchPoint.x;
! ! [trackView layoutIfNeeded];
! }];
! return YES;
}
Animation
#238: Animate the constant.
#238: Call layoutIfNeeded in a block.
Animate layers instead of views.
Layer animation
// jumpy
[UIView animateWithDuration:0.3 delay:0
options:UIViewAnimationOptionAutoreverse
animations:^{
v.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
v.transform = CGAffineTransformIdentity;
}];
// smooth
CABasicAnimation* ba = [CABasicAnimation
animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue
valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];
Animation
#238: Animate the constant.
#238: Call layoutIfNeeded in a block.
Animate layers instead of views.
Drop constraints, use autosizing masks.
Animation
#238: Animate the constant
#238: Call layoutIfNeeded in a block
Animate layers instead of views.
Drop constraints, use autosizing masks.
Use a container view.
Animation
#238: Animate the constant.
#238: Call layoutIfNeeded in a block.
Animate layers instead of views.
Drop constraints, use autosizing masks.
Use a container view.
Use constraints that don’t interfere.
Animation
#238: Animate the constant.
#238: Call layoutIfNeeded in a block.
Animate layers instead of views.
Drop constraints, use autosizing masks.
Use a container view.
Use constraints that don’t interfere.
Set frame in viewDidLayoutSubviews.
Animating Rotations
Fading in/out during rotation
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)to
duration:(NSTimeInterval)duration
{
! // fade away old layout
! [UIView animateWithDuration:duration animations:^{
! for (UIView *view in @[settingsView, creditsView])
! view.alpha = 0.0f;
! }];
}
- (void) didRotateFromInterfaceOrientation:(UIInterfaceOrientation)from
{
! // update the layout for the new orientation
! [self updateViewConstraints];
! [self.view layoutIfNeeded];
! // fade in the new layout
! [UIView animateWithDuration:0.3f animations:^{
! for (UIView *view in @[settingsView, creditsView])
! view.alpha = 1.0f;
! }];
}
Update and animate changes
- (void) willAnimateRotationToInterfaceOrientation:
(UIInterfaceOrientation)to
duration:(NSTimeInterval)duration
{
! [UIView animateWithDuration:duration animations:^{
! ! [self updateViewConstraints];
! ! [self.view layoutIfNeeded];
! }];
}
Calling updates
UIDeviceOrientation newOrientation;
- (void) updateViewConstraints
{
! [super updateViewConstraints];
! [self.view removeConstraints:self.view.constraints];
! if (newOrientation==UIDeviceOrientationPortrait){
! ! // ...
! }
}
- (void) willRotateToInterfaceOrientation:
(UIInterfaceOrientation)toInterfaceOrientation
duration:(NSTimeInterval)duration
{
! newOrientation = toInterfaceOrientation;
! [self updateViewConstraints];
}
References
#202 WWDC 2012: Introduction to Auto Layout for iOS and OS X
#228 WWDC 2012: Best Practices for Mastering Auto Layout
#232 WWDC 2012: Auto Layout by Example
#406 WWDC ’13 Taking Control of Auto Layout in Xcode 5
Cocoa Auto Layout Guide
iOS Auto Layout Demystified
$16

Autolayout