After using SnapKit for a long time, I thought it was just a simple grammar candy at the beginning, but I still felt a bit bumpy when USING it later. Therefore, I went back to the official documents and found several best practices that I had not noticed before, so I wrote them and shared them.

Inset is a high-level abstraction

When I first started using SnapKit, I used offset directly to control the margins:

view.snp.makeConstraints {
    $0.top.left.equalToSuperview().offset(10)
    $0.right.bottom.equalToSuperview().offset(-10)}Copy the code

Offset uses the absolute value. For example, if the bottom of the superview is 300, the bottom of the view will be 300 + (-10).

To simplify the syntax in this case, SnapKit encapsulates a high-level abstraction called inset to help us automatically convert:

switch layoutAttribute {
case .left   : return value.left
case .top    : return value.top
case .right  : return -value.right
case .bottom : return -value.bottom
...
}
Copy the code

With inset, the previous code can be simplified like this:

view.snp.makeConstraints {
    $0.top.left.bottom.right.equalToSuperview().inset(10)
    // Or just use the edges
    $0.edges.equalToSuperview().inset(10)}Copy the code

Inset should be used when describing views in relation to superViews, and offset should be used when describing views in relation to other views in the same hierarchy.

Impossible to ignore

In a view, designers generally give content a uniform margin, similar to the concept of THE PADDING in H5. We often scatter the padding around when constructing constraints:

container.addSubview(a)
container.addSubview(b)

a.snp.makeConstraints {
    $0.top.equalToSuperview().inset(5)
    $0.left.right.equalToSuperview().inset(15)
}

b.snp.makeConstraints {
    $0.top.equalTo(a.snp.bottom).offset(5)
    $0.left.right.equalToSuperview().inset(15)
    $0.bottom.equalToSuperview().inset(5)}Copy the code

It’s a bad thing to have the padding but spread it out. A better way is to use the existing abstract UIEdgeInsets.

When we call equalTo, offset, or inset and pass in a value, we see that the parameter type we pass in is really just ConstraintConstantTarget, which is a protocol that SnapKit uses as a class cluster. A method is used to convert this to CGFloat as the constant of the constraint.

UIEdgeInsets also follow this protocol, so we can handle margins more elegantly:

let containerInsets = UIEdgeInsets(top: 5.left: 15, bottom: 5.right:15)

container.addSubview(a)
container.addSubview(b)

a.snp.makeConstraints {
    $0.top.left.right.equalToSuperview().inset(containerInsets)
}

b.snp.makeConstraints {
    $0.top.equalTo(a.snp.bottom).offset(5)
    $0.left.bottom.right.equalToSuperview().inset(containerInsets)
}
Copy the code

With this code, we can describe the margins between the View and superView in a single line of code most of the time, and it’s easy to change. CGPoint and CGSize also follow this protocol, so you can explore more interesting uses, such as sie.equalto (20).

Use updateConstraints whenever possible when modifying constraints

The native NSLayoutConstraint is used to change the value of constant by referring to a variable, and then changing its constant by reference if necessary.

The same applies to SnapKit. We can get the constraint using the Constraint method and then strong-reference it:

var someConstraint: Constriant?

a.snp.makeConstriants {
    someConstraint = $0.top.equalToSuperview().constraint
    $0.left.equalToSuperview().inset(15)
    $0.bottom.equalToSuperview()
}
Copy the code

But this approach makes the code look messy, and the top and bottom constraints must be split into two lines, referencing only one constraint at a time. A better way is to use the updateConstraints method:

a.snp.makeConstriants {
    $0.top.bottom.equalToSuperview()
    $0.left.equalToSuperview().inset(15)}... a.snp.updateConstraints { $0.top.equalToSuperview().inset(10)}Copy the code

This method walks through all existing constraints and then finds the constraints that you updated in updateConstraints, updating their constant.

The advantage of this is that the syntax is more concise and consistent, making the constraints behave more like properties of the view. However, the disadvantage is obvious, only constant can be updated.

summary

I personally feel that writing good business logic is not an easy task, but the difficulty is not the implementation, but the maintainability and implementation speed, there is still a lot to learn from Best Pratice.

If you think the article is good, you can follow my blog