Programmatically creating Autolayout constraints is famously dense to read, although the strongly-typed visual format makes some easier to parse visually.
With that in mind, which is easier to read?
let subView1 = UIView() let subView2 = UIView let constraint = NSLayoutConstraint(item: subView1, attribute: .left, relatedBy: NSLayoutRelation.equal, toItem: subView2, attribute: .right, multiplier: 1.0, constant: -10) constraint.priority = 900.0 view.addConstraint(constraint)
view.📌(subView1 ⬇️=⬆️ subView2 + 10 ‼️ 900.0)
I wrote this as an exercise after reading a description of Erica Sadun’s talk and some posts of hers on the emoji as function name idea. I happened to read this around the time that I was needing to layout a number of views in code using autolayout and was overwhelmed with the verbosity.
So I started goofing. Basically, I use the “boxed arrow” emoji to indicate which edge is being constrained, and double arrows to indicate height/width. Then and “=” operator to indicate that two edges are constrained.
The “+” operator is overloaded to add a constant to the constraint, and the “‼️” emoji is overloaded to indicate priority. Sadly, I couldn’t find an emoji that was valid for use as an operator and that was as clear as the 📌 for communicating “add constraint, so I named a function “📌”.
Lastly, I probably could have just overloaded “+” again to add the constraints, but I ran out of time and it was simpler to overload ++ for adding different constraints.
Likewise, it would be useful to add “<=”, “>=” operators.
Anyway, I’m pretty happy with this fun project. I think that the example below demonstrates the use the syntax. I have also embedded my full playground as a gist.
and here is the layout code
// add one constraint at a time view.📌(grayView |⬅️ 20.0) //to superview margin view.📌(grayView -⬆️ 20.0) view.📌(grayView ⬇️- 20.0) view.📌(grayView ➡️| 20.0) // add multiple constraints (combined with ++ operator) view.📌(redButton |⬅️ 60 ++ redButton -⬆️ 60 ++ redButton ↕️= 40 ++ redButton ↔️= 40) // can add constants view.📌(redButton ↔️=↔️ blueButton + 20) // can add priorities view.📌(redButton ⬇️=⬆️ blueButton + 100 ‼️ 800.0) view.📌(redButton ⬇️=⬆️ blueButton + 10 ‼️ 900.0) view.📌(redButton |=| blueButton) //align vertical centers view.📌(blueButton ↕️= 100) view.📌((blueButton--orangeButton + 40) ++ (blueButton-=-orangeButton)) //precedence rules require parentheses around constraints that have constants or priorities orangeButton.📌(orangeButton ↕️= 45 ++ orangeButton ↔️= 25)
- I certainly agree that the advantage is purely in readability. typing these would only be feasible with a series of textExpander/Xcode snippets ↩︎