Programmatic UI
Introduction
-
There are 3 types of user interface design approaches as mentioned in User Interface page.
- At Nimble, the two most common ways to layout views
programmatically
are:- NSLayoutConstraint: is a native Swift API to layout views.
- SnapKit: is a domain-specific language (DSL) to make Auto Layout easy on both iOS and macOS.
- In general, the idea of layout views follows these main two steps:
- Creating constraints.
- Activating and deactivating constraints.
NSLayoutConstraint
-
The constraint-based layout system must satisfy the relationship between two user interface objects.
Example:
// 1 - Create constraints let containerViewConstraints = [ containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20.0), containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20.0) ] // 2 - Activate constraints NSLayoutConstraint.activate(containerViewConstraints)
- As the above example, the code has enough two steps to layout
containerView
:- Create constraints by using
NSLayoutAnchor
. - Activate created constraints by
NSLayoutConstraint.activate
.
- Create constraints by using
-
Besides, another way (less preferred) is creating constraints directly from
NSLayoutConstraint
and adding constraints to the view instead of activating it.Example:
// Create constraints by initializing NSLayoutConstraint let leadingConstraint = NSLayoutConstraint( item: contentView, attribute: .leading, relatedBy: .equal, toItem: view, attribute: .leading, multiplier: 1.0, constant: 20.0 ) let trailingConstraint = NSLayoutConstraint( item: contentView, attribute: .trailing, relatedBy: .equal, toItem: view, attribute: .trailing, multiplier: 1.0, constant: -20.0 ) // Activate constraints constraints by addConstraints containerView.addConstraints([ leadingConstraint, trailingConstraint ])
SnapKit
-
SnapKit is exceptionally straightforward to use, and it aims to create a syntax that is much more intuitive for Auto Layout constraints.
Example:
containerView.snp.makeConstraints { $0.leading.trailing.equalToSuperView().inset(20.0) }
-
The two important factors the team should get used to are:
Equality Constraints
and theView Attributes
.-
Equality Constraints:
-
.equalTo
equivalent to NSLayoutConstraint.Relation.equal -
.lessThanOrEqualTo
equivalent to NSLayoutConstraint.Relation.lessThanOrEqual -
.greaterThanOrEqualTo
equivalent to NSLayoutConstraint.Relation.greaterThanOrEqual
-
-
View Attributes table
ViewAttribute NSLayoutAttribute view.snp.left NSLayoutConstraint.Attribute.left view.snp.right NSLayoutConstraint.Attribute.right view.snp.top NSLayoutConstraint.Attribute.top view.snp.bottom NSLayoutConstraint.Attribute.bottom view.snp.leading NSLayoutConstraint.Attribute.leading view.snp.trailing NSLayoutConstraint.Attribute.trailing view.snp.width NSLayoutConstraint.Attribute.width view.snp.height NSLayoutConstraint.Attribute.height view.snp.centerX NSLayoutConstraint.Attribute.centerX view.snp.centerY NSLayoutConstraint.Attribute.centerY view.snp.lastBaseline NSLayoutConstraint.Attribute.lastBaseline
-
-
Pay attention to
priority
,updateConstraints
, orremakeConstraints
to sharp actual implementation.
Discussion
Version Support
-
NSLayoutConstraint
is available on iOS 6. However, from iOS 8, Apple introduces a concept of active state to NSLayoutConstraint. Developers can activate or deactivate a constraint by changing this property and note that only active constraints affect the calculated layout. -
In iOS 9, Apple solves the problem of creation syntax by coming up with
NSLayoutAnchor
. - While iOS 10 or later,
SnapKit
can be used.
Syntax
-
SnapKit
is more convenient thanNSLayoutConstraint
since it makes the code look short and precise, whileNSLayoutConstraint
doesn’t require integrating any external libraries and learning new syntax. External libraries might not be familiar to current or future teammates. -
Although SnapKit is now the preferred option for every project that could be easier and faster for both the development and review phase, it depends on the project process and resources to make a decision that could be more facilitated.
Debug
-
SnapKit
provides the ability to debug view by printing out logs for every constraint. This can be pretty tricky to achieve when usingNSLayoutConstraint
. -
Labels can be tacked on to the end of a constraint chain like so:
Example:
containerView.snp.makeConstraints { $0.leading.equalToSuperView().labeled("containerViewLeadingConstraint") }
Resulting
Unable to simultaneously satisfy constraints.
logs will use constraint label to clarify:"<SnapKit.LayoutConstraint:[email protected]#78 Project.UIView:0x15cf1c870.leading == UIView:0x15cf1b810.leading>"
And showing
Will attempt to recover by breaking constraint
logs that constraint is recovering:"<SnapKit.LayoutConstraint:[email protected]#78 Project.UIView:0x15cf1c870.leading == UIView:0x15cf1b810.leading + x.x>"
Conclusion
- After considering several criteria, deciding to go with
SnapKit
orNSLayoutConstraint
depends on minimum iOS version support or current teammates’ knowledge and experience. - In terms of pros what’s mentioned in Discussion of
SnapKit
, there’s almost no preference to useNSLayoutConstraint
despite being Apple’s default API. However, it’s totally perfect as an alternative if any reasonsSnapKit
is not an option.