用了 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 能夠挖掘的。
以爲文章還不錯的話能夠關注一下個人博客