autolayout primer
DESCRIPTION
This is a presentation I gave at an internal meeting at iCapps on 20131204.TRANSCRIPT
Autolayout PrimerInternal presentation @ iCapps, 2013-12-04
Introduction
Tom Adriaenssen
I love...
‣ ... my wife ‣ ... my 4 kids ‣ ... to code ‣ ... to play a game of squash ‣ ... good beer
I open sourced...... some code:
‣ IIViewDeckController: “An implementation of the sliding functionality found in the Path 2.0 or Facebook iOS apps.”
‣ IIDateExtensions
‣ IIPopoverStatusItem
See: http://github.com/inferis
I made...
... some apps:
Butane Drash
Hi, @10to1!http://getbutane.com http://dra.sh
Agenda
Agenda
‣ What is Autolayout? ‣ What is a constraint? ‣ Autolayout in Xcode designer ‣ Autolayout in code
Autolayout
What is Autolayout?
Auto%Layout%is%a%system%that%lets%you%lay%out%your%app’s%user%interface%by%creating%a%mathematical%description%of%the%relationships%between%the%elements.%%
According to the Apple Docs:
‣ Keywords: ‣ mathematical ‣ relationships
‣ Eh? ‣ Developer defines constraints on/between elements ‣ constraints translate into mathematical functions ‣ UIKit/Appkit tries to solve these functions
What is Autolayout?‣ Correctly using autolayout requires you to change thinking
‣ Autolayout works in a different way than what you were used to
‣ Don't go calculating frames anymore ‣ Define how an element should behave according to it's
peers: ‣ parent ‣ siblings
‣ Don't think in absolute terms, but think in relational terms ‣ Think flexible: it's not because an element has a certain
size at one point, it will have the same size at another point
Constraints
Constrainta%mathematical%representation%of%a%human:expressable%statement%
"the left edge should be 20pt of the superviews left edge"
view.left = (superview.left + 20)
y = m * x + c
(y%=%attribute1%=%view.left)%(x%=%attribute2%=%superview.left)%
(m%=%multiplier%=%1)%(c%=%constant%=%20)
//%firstItem.firstAttribute%{==,<=,>=}%secondItem.secondAttribute%*%multiplier%+%constant%!@property%(readonly,%assign)%id%firstItem;%@property%(readonly)%NSLayoutAttribute%firstAttribute;%@property%(readonly)%NSLayoutRelation%relation;%@property%(readonly,%assign)%id%secondItem;%@property%(readonly)%NSLayoutAttribute%secondAttribute;%@property%(readonly)%CGFloat%multiplier;%!@property%CGFloat%constant;
Constraint‣ two items with an attribute ‣ constant ‣ relation ‣ multiplier ‣ priority level
//%firstItem.firstAttribute%{==,<=,>=}%secondItem.secondAttribute%*%multiplier%+%constant%!@property%(readonly,%assign)%id%firstItem;%@property%(readonly)%NSLayoutAttribute%firstAttribute;%@property%(readonly)%NSLayoutRelation%relation;%@property%(readonly,%assign)%id%secondItem;%@property%(readonly)%NSLayoutAttribute%secondAttribute;%@property%(readonly)%CGFloat%multiplier;%!@property%CGFloat%constant;
Attribute?‣ left ‣ right ‣ top ‣ bottom ‣ leading ~ left or right depending on language settings ‣ trailing ~ right or left depending on language settings ‣ width ‣ height ‣ centerX ‣ centerY ‣ baseline
Constant?‣ physical size or offset
Multiplier?‣ Apply modifier to attribute of source item
‣ Cannot be set using the designer ‣ Can be set in code
Relation?‣ equal ‣ less than or equal ‣ greater than or equal !
‣ if you want just "less than" or "greater than", adjust the constant
Priority‣ constraints with higher priority are satisfied before
constraints with lower priority ‣ Default = UILayoutPriorityRequired (1000) ‣ Other predefined priorities
‣ UILayoutPriorityRequired = 1000 ‣ UILayoutPriorityDefaultHigh = 750
‣ Default content compression priority
‣ UILayoutPriorityDefaultLow = 250 ‣ Default content hugging priority
‣ UILayoutPriorityFittingSizeLevel = 50 ‣ You can use any integer value between 0-1000
Pitfalls‣ constraints are cumulative ‣ constraints do not override each other
‣ adding a second width constraint does not remove or override a previous one
‣ remove first one manually ‣ constraints can cross view hierarchy
‣ add constraint from view to superview of superview
‣ only if scope of view hierarchy uses autolayout! (no custom framesetting)
Intrisic Content Size‣ applicable to leaf views (views with no subviews) ‣ view knows what size it wants to be (eg UIButton) ‣ autolayout will size view to its intristic content size if no
constraints control the width/height
:%(CGSize)intrinsicContentSize;
Returns%the%natural%size%for%the%receiving%view,%considering%only%properties%of%the%view%itself.%
‣ You can override this method in a subclass to change the default behavior
‣ return UIViewNoIntrinsicMetric when there's no intristic size defined for an axis
Compression resistance & Content hugging‣ Content Compression resistance?
‣ defines how the view's frame resist compressing it's content
‣ Content hugging? ‣ defines how the view's frame should hug it's
content
Compression resistance & Content huggingSay you've got button like this: % |[%%%%%%%Click%Me%%%%%%]|%
and you've pinned the edges to a larger superview with priority 500. !Then, if hugging priority > 500 it'll look like this: % |[Click%Me]%%%%%%%%%%%%%|%
If hugging priority < 500 it'll look like this: % |[%%%%%%%Click%Me%%%%%%]|%
!If the superview now shrinks and if the compression resistance priority > 500, it'll look like this % |[Click%|Me]%
else if compression resistance priority < 500, it could look like this: % |[Cli..]|
Autolayout in Xcode designer
Demo
Autolayout in code
Autolayout in code: 3 options‣ Write constraints manually
‣ HEAD WILL EXPLODE ‣ Use visual format
‣ HEAD WILL EXPLODE MOAR ‣ Use UIView+AutoLayout Cocoapod
‣ Provides descriptive methods creating constraints
‣ Still verbose but quite readable ‣ Best of both worlds
Autolayout in code‣ Important note when creating constraints in code ‣ If you create a view manually, use: !
!
‣ if you don’t, you’ll get a lot of constraint errors!
view%=%[UIView%new];%view.translatesAutoresizingMaskIntoConstraints%=%NO;
UIView+AutoLayout‣ Available as a CocoaPod
‣ Implements a category on UIView. ‣ Easy creation of 1 or more NSLayoutConstraints.
‣ Some methods return 1 constraint, some an NSArray containing constraints
‣ Does not add constraints, just creates them ‣ you need to add them yourself
:(void)addConstraint:(NSLayoutConstraint%*)constraint;%:(void)addConstraints:(NSArray%*)constraints;
UIView+AutoLayout
‣ Don't use: translatesAutoresizingMaskIntoConstraints !% view%=%[UIView%newAutoLayoutView];%% //%or%% view%=%[[UIView%alloc]%initForAutoLayout];
Creating an autolayouted view
UIView+AutoLayout
:%(NSLayoutConstraint%*)autoPinEdgeToSuperviewEdge:(ALEdge)edge%withInset:(CGFloat)inset;%
‣ Pins the given edge of the view to the same edge of the superview with an inset.
!:%(NSLayoutConstraint%*)autoPinEdgeToSuperviewEdge:(ALEdge)edge%withInset:(CGFloat)inset%relation:(NSLayoutRelation)relation;%
‣ Pins the given edge of the view to the same edge of the superview with an inset as a maximum or minimum.
!:%(NSArray%*)autoPinEdgesToSuperviewEdgesWithInsets:(UIEdgeInsets)insets;%
‣ Pins the edges of the view to the edges of its superview with the given edge insets.
Pin to superview edges
UIView+AutoLayout
:%(NSLayoutConstraint%*)autoPinEdge:(ALEdge)edge%%%%%%%%%%%%%%%%toPositionInSuperview:(CGFloat)value;%
‣ Pins the given edge of the view to a fixed position (X or Y value, depending on edge) in the superview.
Pin at point in superview
UIView+AutoLayout
:%(NSArray%*)autoCenterInSuperview;%
‣ Centers the view in its superview. !:%(NSLayoutConstraint%*)autoCenterInSuperviewAlongAxis:(ALAxis)axis;%
‣ Centers the view along the given axis (horizontal or vertical) within its superview. !:%(NSLayoutConstraint%*)autoPinCenterAxis:(ALAxis)axis%%% % % % %%%toPositionInSuperview:(CGFloat)value;%
‣ Pins the given center axis of the view to a fixed position (X or Y value, depending on axis) in the superview.
Centering in superview
UIView+AutoLayout
:%(NSLayoutConstraint%*)autoPinEdge:(ALEdge)edge%toEdge:(ALEdge)toEdge%ofView:(UIView%*)peerView;%
‣ Pins an edge of the view to a given edge of another view. !:%(NSLayoutConstraint%*)autoPinEdge:(ALEdge)edge%toEdge:(ALEdge)toEdge%ofView:(UIView%*)peerView%withOffset:(CGFloat)offset;%
‣ Pins an edge of the view to a given edge of another view with an offset. !:%(NSLayoutConstraint%*)autoPinEdge:(ALEdge)edge%toEdge:(ALEdge)toEdge%ofView:(UIView%*)peerView%withOffset:(CGFloat)offset%relation:(NSLayoutRelation)relation;%
‣ Pins an edge of the view to a given edge of another view with an offset as a maximum or minimum.
Pin to other views
UIView+AutoLayout
:%(NSLayoutConstraint%*)autoAlignAxis:(ALAxis)axis%%%%%%%%%%%%%%%%%%%%%%%toSameAxisOfView:(UIView%*)peerView;%
‣ Aligns an axis of the view to the same axis of another view. !:%(NSLayoutConstraint%*)autoAlignAxis:(ALAxis)axis%%%%%%%%%%%%%%%%%%%%%%%toSameAxisOfView:(UIView%*)peerView%%%% % % % % %%%%%%withOffset:(CGFloat)offset;%
‣ Aligns an axis of the view to the same axis of another view with an offset.
Aligning views
UIView+AutoLayout
:%(NSArray%*)autoSetDimensionsToSize:(CGSize)size;%
‣ Sets the view to a specific size. !:%(NSLayoutConstraint%*)autoSetDimension:(ALDimension)dimension%%% % % % % % % % %toSize:(CGFloat)size;%
‣ Sets the given dimension of the view to a specific size. !:%(NSLayoutConstraint%*)autoSetDimension:(ALDimension)dimension%%%%% % % % % % % % %toSize:(CGFloat)size%%% % % % % % % %%%relation:(NSLayoutRelation)relation;%
‣ Sets the given dimension of the view to a specific size as a maximum or minimum.
View dimensions
UIView+AutoLayout
:%(NSLayoutConstraint%*)autoMatchDimension:(ALDimension)dimension%toDimension:(ALDimension)toDimension%ofView:(UIView%*)peerView;%
‣ Matches a dimension of the view to a given dimension of another view. :%(NSLayoutConstraint%*)autoMatchDimension:(ALDimension)dimension%toDimension:(ALDimension)toDimension%ofView:(UIView%*)peerView%withOffset:(CGFloat)offset;%
‣ Matches a dimension of the view to a given dimension of another view with an offset. :%(NSLayoutConstraint%*)autoMatchDimension:(ALDimension)dimension%toDimension:(ALDimension)toDimension%ofView:(UIView%*)peerView%withOffset:(CGFloat)offset%relation:(NSLayoutRelation)relation;%
‣ Matches a dimension of the view to a given dimension of another view with an offset as a maximum or minimum.
:%(NSLayoutConstraint%*)autoMatchDimension:(ALDimension)dimension%toDimension:(ALDimension)toDimension%ofView:(UIView%*)peerView%withMultiplier:(CGFloat)multiplier;%
‣ Matches a dimension of the view to a multiple of a given dimension of another view. :%(NSLayoutConstraint%*)autoMatchDimension:(ALDimension)dimension%toDimension:(ALDimension)toDimension%ofView:(UIView%*)peerView%withMultiplier:(CGFloat)multiplier%relation:(NSLayoutRelation)relation;%
‣ Matches a dimension of the view to a multiple of a given dimension of another view as a maximum or minimum.
View dimension matching
UIView+AutoLayout
+%(void)autoSetPriority:(UILayoutPriority)priority%%%%%%%%%%%forConstraints:(ALConstraintsBlock)block;%
‣ Sets the constraint priority to the given value for all constraints created using the UIView+AutoLayout category API within the given constraints block.
‣ NOTE: This method will have no effect (and will NOT set the priority) on constraints created or added using the SDK directly within the block!
‣ Use the auto… methods of UIView+AutoLayout
Priorities
UIView+AutoLayout
:%(void)autoRemoveConstraintsAffectingView;%
‣ Removes all explicit constraints that affect the view. :%(void)autoRemoveConstraintsAffectingViewAndSubviews;%
‣ Recursively removes all explicit constraints that affect the view and its subviews. Additional%methods%if%you%do%want%to%remove%the%:%(void)autoRemoveConstraintsAffectingViewIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints;%
‣ Removes all constraints that affect the view, optionally including implicit constraints.
:(void)autoRemoveConstraintsAffectingViewAndSubviewsIncludingImplicitConstraints:(BOOL)shouldRemoveImplicitConstraints;%
‣ Recursively removes all constraints from the view and its subviews, optionally including implicit constraints.
Removal of constraints
UIView+AutoLayoutRemoval of constraints
‣ A little bit of a warning when removing constraints: ‣ The constraint solving engine is not optimised for
the removal of constraints ‣ Removing a lot of constraints can have serious
impact on performance ‣ Use with care and in small quantities
‣ You can change the priority of a constraint to “disable” it (but you have to remember the original value to reenable it)
UIView+AutoLayout
‣ category on NSArray doing the same for groups of views
‣ category on NSLayoutConstraint to remove a constraint from the view it's attached to
Other stuff
Protips‣ Where to add which constraints?
‣ When constraints only apply to 1 view (eg setting dimensions) ‣ create on view ‣ add to view
‣ When constraints apply to more than 1 view eg pin one view to another ‣ create on target view ‣ add to common superview of both views (usually the
same)
Protips ‣ Check for autotranslated autoresizing constraints ‣ don’t forget translatesAutoresizingMaskIntoConstraints
‣ Display the view hierarchy from the root to find where things go wrong ‣ errors don’t provide any context !
‣ look for address of view giving errors, and then you’ll get an idea of what context the error is happing in
po%[[[[UIApplication%sharedApplication]%windows]%objectAtIndex:0]%recursiveDescription]
Protips‣ Don’t assume a view has a fixed size
‣ (unless you give it a size constraint)
‣ initWithFrame: not really useful anymore ‣ Don’t use frame/bounds calculations in constraints
‣ exception: in layoutSubViews
‣ Try to minimalise the number of constraints ‣ solving takes time ‣ more constraints, more complex
Protips‣ animating constraints
‣ set constraints outside animation block ‣ call layoutIfNeeded in animation ‣ Make sure you do this on the correct “top level
view” otherwise nothing will animate!
self.offsetConstraint.constant%=%[self%calculateOffset];%[UIView%animationWithDuration:0.3%animations:^{%% [self.view%layoutIfNeeded];%}];
Protips‣ when changing content:
‣ don’t forget to update constraints ‣ call setNeedsUpdateConstraints
‣ let the system decide when to update
‣ or updateConstraintsIfNeeded ‣ immediate action
‣ only needed when your constraint change might affect other constraints
‣ don’t forget to relayout your views ‣ call setNeedsLayout ‣ or layoutIfNeeded
Useful References‣ Apple’s autolayout documentation: ‣ reference: https://developer.apple.com/library/ios/
documentation/userexperience/conceptual/AutolayoutPG/Introduction/Introduction.html
‣ Martin Pilkington’s iOSDevUK2013 slides on autolayout solving ‣ http://www.iosdevuk.com/storage/talks2013/
MartinPilkington.pdf ‣ UIView+AutoLayout ‣ https://github.com/smileyborg/UIView-AutoLayout
Thanks for listening.
Twitter: @inferis App.Net: @inferis E-mail: [email protected] vCard: http://inferis.org
Questions? Contact me: