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
programmaticallyare:- 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
NSLayoutConstraintand 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 Constraintsand theView Attributes.-
Equality Constraints:
-
.equalToequivalent to NSLayoutConstraint.Relation.equal -
.lessThanOrEqualToequivalent to NSLayoutConstraint.Relation.lessThanOrEqual -
.greaterThanOrEqualToequivalent 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, orremakeConstraintsto sharp actual implementation.
Discussion
Version Support
-
NSLayoutConstraintis 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,
SnapKitcan be used.
Syntax
-
SnapKitis more convenient thanNSLayoutConstraintsince it makes the code look short and precise, whileNSLayoutConstraintdoesn’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
-
SnapKitprovides 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 constraintlogs 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
SnapKitorNSLayoutConstraintdepends 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 useNSLayoutConstraintdespite being Apple’s default API. However, it’s totally perfect as an alternative if any reasonsSnapKitis not an option.