用了 SnapKit 好久,一开始以为这就是个很简单的语法糖,后面用着用着仍是以为有点磕磕绊绊,因此又回去看过了一遍官方文档,发现了几个 best practice 是我以前一直没留意到的,就写出来分享一下。git
刚开始使用 SnapKit 时,我都是直接使用 offset
来控制边距的:github
view.snp.makeConstraints {
$0.top.left.equalToSuperview().offset(10)
$0.right.bottom.equalToSuperview().offset(-10)
}
复制代码
offset
使用的是绝对值,例如说 superview
的 bottom
是 300 时,那 view
的 bottom
就会是 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 时,应该使用 offset
。code
在一个 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 但却分散去处理是一件很糟糕的事情,更好的方式是使用已有的抽象 UIEdgeInsets
。get
在调用 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 之间的边距,并且修改起来也很方便。另外 CGPoint
和 CGSize
也遵循了这个协议,你们能够去挖掘更多有趣的用法,例如 size.equalTo(20)
。
原生的 NSLayoutConstraint
在使用时,若是咱们须要修改 constant
的值,通常会使用一个变量去引用,有须要时再去经过这个引用修改它的 constant
。
一样的方式也适用于 SnapKit,咱们能够经过 constraint
方法去获取到这个约束,而后强引用它:
var someConstraint: Constriant?
a.snp.makeConstriants {
someConstraint = $0.top.equalToSuperview().constraint
$0.left.equalToSuperview().inset(15)
$0.bottom.equalToSuperview()
}
复制代码
但这种方式会让代码看起来很混乱,而且 top
跟 bottom
的约束必须拆成两行,一次性只能引用一个约束。更好的方式是使用 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 能够挖掘的。
以为文章还不错的话能够关注一下个人博客