SnapKit 最佳实践

用了 SnapKit 好久,一开始以为这就是个很简单的语法糖,后面用着用着仍是以为有点磕磕绊绊,因此又回去看过了一遍官方文档,发现了几个 best practice 是我以前一直没留意到的,就写出来分享一下。git

inset 是个高级抽象

刚开始使用 SnapKit 时,我都是直接使用 offset 来控制边距的:github

view.snp.makeConstraints {
    $0.top.left.equalToSuperview().offset(10)
    $0.right.bottom.equalToSuperview().offset(-10)
}
复制代码

offset 使用的是绝对值,例如说 superviewbottom 是 300 时,那 viewbottom 就会是 300 + (-10)swift

为了简化在这种状况下的语法,SnapKit 封装了一个高级抽象 inset,帮咱们自动转换:spa

switch layoutAttribute {
case .left   : return value.left
case .top    : return value.top
case .right  : return -value.right
case .bottom : return -value.bottom
...
}
复制代码

使用 inset,以前的代码就能够简化成这样:设计

view.snp.makeConstraints {
    $0.top.left.bottom.right.equalToSuperview().inset(10)
    // 或者直接使用 edges
    $0.edges.equalToSuperview().inset(10)
}
复制代码

总结一句就是,在描述 view 与 superview 关系时,应该使用 inset,而描述 view 与同一层级的其它 view 时,应该使用 offsetcode

不可忽视的 ConstraintConstantTarget

在一个 view 里,通常来讲设计师都会给 content 一个统一的边距,相似于 h5 里 padding 的概念,在构建约束时咱们常常会把这个 padding 分散到各处:文档

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)
}
复制代码

同是 padding 但却分散去处理是一件很糟糕的事情,更好的方式是使用已有的抽象 UIEdgeInsetsget

在调用 equalTo, offset 或者 inset 传入数值时,咱们会发现传入的参数类型实际上只有 ConstraintConstantTarget,这是一个协议,SnapKit 把它做为一个类簇在使用,经过一个方法将它转化为 CGFloat 来做为 constraint 的 constant博客

UIEdgeInsets 也遵循了这个协议,因此咱们能够更加优雅地去处理边距:it

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)
}
复制代码

经过这样的代码,绝大部分时候咱们均可以只用一行代码去描述 view 跟 superview 之间的边距,并且修改起来也很方便。另外 CGPointCGSize 也遵循了这个协议,你们能够去挖掘更多有趣的用法,例如 size.equalTo(20)

修改约束时尽可能使用 updateConstraints

原生的 NSLayoutConstraint 在使用时,若是咱们须要修改 constant 的值,通常会使用一个变量去引用,有须要时再去经过这个引用修改它的 constant

一样的方式也适用于 SnapKit,咱们能够经过 constraint 方法去获取到这个约束,而后强引用它:

var someConstraint: Constriant?

a.snp.makeConstriants {
    someConstraint = $0.top.equalToSuperview().constraint
    $0.left.equalToSuperview().inset(15)
    $0.bottom.equalToSuperview()
}
复制代码

但这种方式会让代码看起来很混乱,而且 topbottom 的约束必须拆成两行,一次性只能引用一个约束。更好的方式是使用 updateConstraints 方法:

a.snp.makeConstriants {
    $0.top.bottom.equalToSuperview()
    $0.left.equalToSuperview().inset(15)
}

...

a.snp.updateConstraints {
    $0.top.equalToSuperview().inset(10)
}
复制代码

这个方法会遍历现有的全部约束,而后找到你在 updateConstraints 里更新的约束,更新它们的 constant

这么作的好处就是语法更简洁一致,让约束表现得更像是 view 的属性。但缺点也很明显,只能更新 constant

小结

我我的感受写好业务逻辑也不是一件容易的事情,但难度不是在于实现,而是可维护性跟实现速度,这里面仍是有不少 best pratice 能够挖掘的。

以为文章还不错的话能够关注一下个人博客

相关文章
相关标签/搜索