SnapLayout

Satinder Singh
3 min readMay 8, 2017

--

In the programmatic AutoLayout world, code can become very hairy, very fast. When Apple introduced NSLayoutConstraint, developers were ecstatic about its ability. Sadly, it was simply too much code and wasn’t the best for readability. Apple then created the factory class NSLayoutAnchor to reduce the code. The code was more readable and understandable. However, it still felt it could be further condensed. This is where SnapLayout comes to the rescue. SnapLayout is built entirely in Swift and leverages the power of AutoLayout with an amazingly concise API. So lets dive in!

SnapLayout vs NSLayoutAnchor

Lets take a simple tableView who should be constrained to a view controller’s view.

// SnapLayout
tableView.snap(top: 0, leading: 0, bottom: 0, trailing: 0)
// NSLayoutAnchor
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true

SnapLayout will apply the necessary constraints relative to the calling view’s superview unless otherwise specified. In this case, SnapLayout will constrain the tableView to its superview. Additionally, SnapLayout will take care of translatesAutoresizingMaskIntoConstraints and set all constraints to active unless otherwise specified. Since this is a very common case in development to simply pin all four sides of a view to its superview, SnapLayout provides a handy shortcut: tableView.snap(constants: .zero)

Concise API

SnapLayout offers a plethora of options. The parameters seen above all have default values of nil. Why you may ask? It was designed to reduce overall code but not at the cost of readability. Imagine a scenario where a label needs to be constrained just to the top, leading, and trailing.

titleLabel.snap(top: 8, leading: 8, trailing: 16)

This line is not cluttered with constraints that are not applied. What if you have a circle view who needs a width and height constraint but still needs to be totally centered.

circleView.snap(width: 26, height: 26, centerX: 0, centerY: 0)

SnapLayout also provides the option of supplying a config if developers prefer to wrap their constraints into a single data structure.

let config = SnapConfig(width: 26, height: 26, centerX: 0 , centerY: 0)
circleView.snap(constants: config)

Imagine a view who has multiple configs that needs to be applied based on a certain user action? You can simply snap those additional configs as well to the view at the appropriate time.

Adjacent Views

How about snapping between views? A common scenario is to have a leading label and trailing label. SnapLayout offers a solution for these adjacent labels who need to be constrained.

trailingLabel
.snap(leadingView: leadingLabel, constant: 16)
.snap(to: leadingLabel, top: 0)

Did you notice? SnapLayout supports chaining! The trailingLabel has two constraints applied. The first constraint is to create a 16 distance constraint to the leadingLabel where the leadingView is the leadingLabel. Next, SnapLayout creates a constraint from the trailingLabel’s top constraint with the leadingLabel’s top constraint. SnapLayout offers methods to handle additional adjacent constraint situations such as trailingView, bottomView, topView, and topView.

Changing Constraints

Whenever a snap occurs, SnapLayout returns a SnapManager. This handy class neatly organizes the created constraints into a readable data structure.

let snapManager = rectangleView
.snap(top: 48, leading: 16, bottom: 16, trailing: 16)
.snap(height: 40, isActive: false)

All of the snaps are automatically synced and accumulated into one object. This SnapManager has access to all of the created constraints through member variables. To name a few: top, leading, width, centerX, etc.

Notice the last line in the last code example. There is an isActive argument. SnapLayout is informed to only create the height constraint and not activate it. Lets see what we can do with this snapManager.

snapManager.height?.priority = 999
snapManager.height?.isActive = true

Since the member variables of snapManager are mostly NSLayoutConstraint, you can adjust them as need be.

More Examples

SnapLayout’s example project is a great place to see more SnapLayout code in action. Just run the following line in terminal

pod try SnapLayout

--

--