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 能夠挖掘的。

以爲文章還不錯的話能夠關注一下個人博客

相關文章
相關標籤/搜索