Auto Layout Shorthand (ALS) is an alternative system for creating and adding Auto Layout constraints.
It feels kind of like CSS, though more powerful and without HTML's frustrating default layout model.
Here's a simple example to introduce ALS:
[iconView als_addConstraints:@{
@"left ==": als_superview,
@"width ==": @(kIconWidth),
@"top ==": als_superview,
@"height ==": @(kIconHeight),
}];
Here's mostly1 the same example using the Visual Format Language (VFL):
[iconView.superview addConstraints:@[
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[iconView(kIconWidth)]"
options:0
metrics:NSDictionaryOfVariableBindings(kIconWidth)
views:NSDictionaryOfVariableBindings(iconView)],
[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[iconView(kIconHeight)]"
options:0
metrics:NSDictionaryOfVariableBindings(kIconHeight)
views:NSDictionaryOfVariableBindings(iconView)],
]];
And mostly2 the same example using +[NSLayoutConstraint constraintWithItem:…]
:
[iconView.superview addConstraints:@[
[NSLayoutConstraint constraintWithItem:iconView
attribute:NSLayoutAttributeLeft
relatedBy:NSLayoutRelationEqual
toItem:iconView.superview
attribute:NSLayoutAttributeLeft
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:iconView
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:kIconWidth],
[NSLayoutConstraint constraintWithItem:iconView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:iconView.superview
attribute:NSLayoutAttributeTop
multiplier:1.0
constant:0.0],
[NSLayoutConstraint constraintWithItem:iconView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:kIconHeight],
]];
Auto Layout Shorthand is a poor man's DSL wedged into a normal Objective-C dictionary literal.
Each key-value pair contains enough information to create one NSLayoutConstraint. This stands in contrast to VFL, where one string can be used to generate multiple constraints.
The dictionary key encodes two pieces of information: the NSLayoutConstraint's firstAttribute
and its relation
. Here's some examples:
@"width >="
@"height <="
@"centerX =="
For the first part of the key, the attribute, every NSLayoutAttribute
is supported except NSLayoutAttributeNotAnAttribute
. See the ALS Dictionary Key Name column below (we'll get to ALS Dictionary Value Name in a moment):
NSLayoutAttribute constant | ALS Dictionary Key Name | ALS Dictionary Value Name |
---|---|---|
NSLayoutAttributeLeft | left | als_left |
NSLayoutAttributeRight | right | als_right |
NSLayoutAttributeTop | top | als_top |
NSLayoutAttributeBottom | bottom | als_bottom |
NSLayoutAttributeLeading | leading | als_leading |
NSLayoutAttributeTrailing | trailing | als_trailing |
NSLayoutAttributeWidth | width | als_width |
NSLayoutAttributeHeight | height | als_height |
NSLayoutAttributeCenterX | centerX | als_centerX |
NSLayoutAttributeCenterY | centerY | als_centerY |
NSLayoutAttributeBaseline | baseline | als_baseline |
The second part of the dictionary key encodes the NSLayoutRelation
in the obvious manner:
NSLayoutRelation constant | Auto Layout Shorthand equivalent |
---|---|
NSLayoutRelationLessThanOrEqual | <= |
NSLayoutRelationEqual | == |
NSLayoutRelationGreaterThanOrEqual | >= |
The dictionary value encodes either a relation or a constant. Simple relations and simple constants are directly assigned:
@"top ==": headerView.als_bottom
@"width ==": @(42)
Let's talk about headerView.als_bottom
some more. als_bottom
is a method added as a category to UIView
. Auto Layout Shorthand adds a suite of methods, one for each NSLayoutAttribute
. That's the ALS Dictionary Value Name column above.
These categories enable you to refer to both a view and an attribute in one expression. The result is a simple class that just packages up both of them into one object that's later consumed by -[UIView(AutoLayoutShorthand) als_addConstraints:]
.
You can use a dictionary to specify more complex constraints:
@"top ==": @{als_view:headerView.als_bottom, als_constant:@(10)},
@"width ==": @{als_constant:@(42), als_priority:@(UILayoutPriorityDefaultHigh)]
Supported keys are:
Auto Layout Shorthand Key | Corresponding NSLayoutConstraint property |
---|---|
als_view | secondItem |
als_multiplier | multiplier |
als_constant | constant |
als_priority | priority |
Finally, VFL has @"|"
, which represents the superview. als_superview
is ALS's version of the same thing.
-
More concise than
+[NSLayoutConstraint constraintWithItem:…]
but just as powerful. Actually, just a smidge more powerful since you can specify the constraint's priority at creation time. -
Easier to read+understand than
+[NSLayoutConstraint constraintWithItem:…]
. -
Often more concise than even Visual Format Language, yet more powerful (Auto Layout Shorthand can specify centerX and centerY).
-
Refactoring-friendly. Visual Format Language strings are opaque to Xcode's refactoring support. This results in nasty runtime exceptions if you use refactoring to rename a variable or property and forget to update any corresponding VFL string.
-
View Property-friendly. This code doesn't work:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[self.iconView(32)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(self.iconView)];
apparently because of the
self.
. One work-around is to access the ivar directly:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_iconView(32)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_iconView)];
which I don't much care for since it bypasses the accessor. I recommend creating the dictionary yourself:
[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[iconView(32)]" options:0 metrics:nil views:@{@"iconView": self.iconView}];
or using ALS.
-
Built-in Closest-Common-Superview Discovery. When relating attributes across views, Auto Layout Shorthand automatically calculates the views' closest common superview and adds the generated constraints there. This is the Apple-recommended place to put your constraints.
-
Another Dependancy. Not that bad though, since it's a self-contained .h/.m pair.
-
Another thing to learn. You probably have to learn VFL anyway to understand Auto Layout's debugging logs.
-
Encourages you to think of constraints being applied to the target view itself instead of the superview they're actually added to. I think removing the level of indirection is worth it.
-
Like Only God Can Create A Tree, Only VFL Can Create NSSpacers. Fortunately ALS plays nicely with VFL, so use VFL if you want to take advantage of spacers.
-
Write an example apps to showcase common scenarios.
-
Either upgrade
als_superview
to a UIView or remove it altogether. Probably the former -- it's not strictly needed (you can always justmyview.superview
, but the conceptual clarity is worth a more-complicated implementation AFAICS.
-
[CHANGE] Allow either view to be the lowest common ancestor. (Andrew Hershberger)
-
[FIX] Implicit conversion warnings. (Andrew Hershberger)
-
[FIX] Priority doesn't work. (Joe Szymanski)
-
[NEW] Improved handling for groups of constraints (the common case):
-
als_addConstraints: now returns an array of the constraints its created.
-
als_activateConstraints and als_deactivateConstraints category methods on NSArray allow enabling and disabling groups of NSLayoutConstraints.
Coupled with als_addConstraints: above, this allows you to create groups of constraints, easily switching them on or off based on user interaction and/or application state.
-
als_hostView and als_setHostView: category methods on NSLayoutConstraint handle the to-one nature (
(UI|NS)View <->> NSLayoutConstraint
) of views and their constraints and to keep track of which host view a constraint has been assigned to so it can be activated (added) and deactivated (removed) easily at runtime. -
als_isActive and als_setActive: category methods on NSLayoutConstraint to provide individual constraint activation control. Used by als_activateConstraints & als_deactivateConstraints.
-
This replaces the idea that I'd add a way to get/set constraints by their ALS keys previously mentioned in the TODO section. Also the idea to allow overwriting of previously-set constraints.
- [DEV] Re-unify UIView and NSView implementations.
- [NEW] Add NSView support. (Tony Arnold)
- [FIX] Make Closest-Common-Superview a little more forgiving.
-
Initial version.
As its Semantic Version suggests, its interface may still change in client-breaking ways.
-
Actually
+[NSLayoutConstraint constraintsWithVisualFormat:…]
will create a constraint with an attribute ofNSLayoutAttributeLeading
where the example above usesNSLayoutAttributeLeft
. ALS does support@"leading =="
in addition to@"left =="
, I just wanted to make the example straightforward to folks who haven't learned about Auto Layout's Right-To-Left text system support yet. -
Same deal as 1.