AutoLayoutBuilder —My Swift Package to Reduce Boilerplate Code
Leverage @resultBuilder to create a DSL for UIView constraints
We are going to solve a few problems with this DSL:
- Setting
translatesAutoresizingMaskToConstrants
tofalse
- Repeating the same
anchor
twice - Repeating the same
constant
multiple times - Code structure: Layout code can be all over the place, this DSL aims to solve that through the use of nesting
Typically, when using auto-layout we have many blocks of code like:
This is already starting to become hard to read and we’ve only added one view, what happens when we have 10 views?
No wonder developers hate it when they need to hunt down an auto-layout bug, there’s so much reading involved!
Most developers are lazy. With that in mind, let’s remove all of the cruft and make this more succinct:
Let’s see how we can achieve this…
First, we’ll need is a way to refer to singular and arrays of NSLayoutConstraints
in the same block, we can do this with a protocol
.
Second, the addSubview
is utilising a @resultBuilder
which allows us to collect all of the NSLayoutConstraints
we want to apply.
At this point we actually have all we need to do something like this:
That’s already a massive improvement over what we had at the beginning, but let’s continue…
In order to make our constraints more readable we’re going to need to store some information about them, for the sake of this example I’m just going to reference the four edge constraints we are going to use.
That provides some anchors that we can now reference/combine in our ConstraintBuilder
, lets implement the ConstraintBuilding
protocol first…
There you can see our anchors being used in those 4 functions, by putting this in a protocol we can extend other types with build
this allows us to chain the constraints (i.e. .leading().trailing()
).
Now let’s implement this protocol in our ConstraintBuilder
struct. For the sake of this article, I’m just going to simplify this and just create the equalToSuperview()
function.
In the above example you can see we can combine
with another constraint inside our build
function, this is what allows us to chain our constraints. We can now layout our redView
like so:
Since all of these values are 20
we could combine this into a single function:
Now we can do what we set out to do:
We can actually nest these calls as well:
Thanks for reading!
If you’re interested in including it in your own project, there is information about the Swift Package below, it allows you to write even more succinct code with relative constraints like so:
Swift Package
The Swift Package contains vastly more functionality than described above, things like:
- Configuration blocks within
@AutoLayoutBuilder
blocks - Constraint chaining before calling an
equalTo
function - Various
equalTo
functions that allow us to link toUILayoutGuide
or other views. [NSLayoutConstraint]
storage via thestore(in:)
function- Operators (
==
,<=
,>=
) to clean up layout code - Setting multipliers for
NSLayoutDimensions
- Setting
UILayoutPriority
during constraint creation - Targeted management of constraints within
[NSLayoutConstraint]
arrays identified usingNSLayoutConstraint.Attribute
(setting constant, priority) - …and much more!