連續(xù)兩個(gè)多月高強(qiáng)度的工作山涡,每天幾乎加班到8點(diǎn)才下班,項(xiàng)目在今天上午終于是提交到 App Store 了必怜。整個(gè)人瞬時(shí)如釋重負(fù)肉拓,但卻有種空虛感,不知道做什么了梳庆。再看下SnapKit吧暖途。發(fā)現(xiàn)之前一直認(rèn)為就那么用來設(shè)置約束即可,沒留意到的地方還挺多膏执。下面分別概述下驻售。
一、inset 和 offset
相信大部分小伙伴們都是使用 offset 來控制邊距的吧更米。
cciView.snp.makeConstraints { (make) in
make.top.equalTo(researchView.snp.bottom).offset(kHeight.d10)
make.left.equalTo(10)
make.right.equalTo(-10)
make.bottom.equalTo(bottomView.snp.bottom)
}
其實(shí) offset 使用的是絕對(duì)值欺栗,尤其是設(shè)置右、下約束的時(shí)候征峦,子控件相對(duì)于父控件都需要加-號(hào)迟几。這一點(diǎn)使用久了,和蘋果的 xib 比起來栏笆,或多或少覺得有點(diǎn)不太合理类腮。其實(shí)該框架是有 inset 來抽象控制的。下面貼下框架的源碼:
public class ConstraintMakerEditable: ConstraintMakerPriortizable {
@discardableResult
public func multipliedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
self.description.multiplier = amount
return self
}
@discardableResult
public func dividedBy(_ amount: ConstraintMultiplierTarget) -> ConstraintMakerEditable {
return self.multipliedBy(1.0 / amount.constraintMultiplierTargetValue)
}
@discardableResult
public func offset(_ amount: ConstraintOffsetTarget) -> ConstraintMakerEditable {
self.description.constant = amount.constraintOffsetTargetValue
return self
}
@discardableResult
public func inset(_ amount: ConstraintInsetTarget) -> ConstraintMakerEditable {
self.description.constant = amount.constraintInsetTargetValue
return self
}
}
使用 inset蛉加,之前的代碼就可以簡(jiǎn)化成這樣(只是舉例):
make.top.equalTo(researchView.snp.bottom).offset(kHeight.d10)
make.left.equalTo(10)
make.right.equalToSuperview().inset(10)
make.bottom.equalTo(bottomView.snp.bottom)
}
總結(jié)下來就是:在描述 view 與 superview 關(guān)系時(shí)蚜枢,應(yīng)該使用 inset,而描述 view 與同一層級(jí)的其它 view 時(shí)针饥,應(yīng)該使用 offset厂抽。
二、ConstraintConstantTarget
在布局 view 的時(shí)候丁眼,一般來說設(shè)計(jì)師都會(huì)給 content 一個(gè)統(tǒng)一的邊距筷凤,類似于 html 中的 padding,在構(gòu)建約束時(shí)我們經(jīng)常會(huì)把這個(gè) padding 分散到各處户盯。但事實(shí)上,將 padding 分散去處理是一件很糟糕的事情饲化,代碼不美觀是其次莽鸭,最重要的是后期維護(hù)起來費(fèi)時(shí)費(fèi)力,更好的方式是使用已有的抽象 UIEdgeInsets吃靠。
在調(diào)用 equalTo, offset 或者 inset 傳入數(shù)值時(shí)硫眨,我們會(huì)發(fā)現(xiàn)傳入的參數(shù)類型實(shí)際上只有 ConstraintConstantTarget,這是一個(gè)協(xié)議巢块,SnapKit 把它作為一個(gè)類簇在使用礁阁,通過一個(gè)方法將它轉(zhuǎn)化為 CGFloat 來作為 constraint 的 constant巧号。
UIEdgeInsets 也遵循了這個(gè)協(xié)議,所以我們可以更加優(yōu)雅地去處理邊距:
// 如果視覺稿中所有的頁面的左右邊距都遵循左右距離相同姥闭,該屬性可以改為全局屬性丹鸿。
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)
}
這樣,后期修改起來會(huì)很容易棚品,代碼也簡(jiǎn)潔了很多靠欢。另外 CGPoint 和 CGSize 也遵循了這個(gè)協(xié)議,大家可以去研究下更多有趣的用法铜跑,例如 size.equalTo(20)门怪。
三、修改約束盡量用 updateConstraints
如果要更新布局約束锅纺,小弟之前的做法是仿照蘋果掷空,用局部變量來引用,然后更新囤锉。如下:
// 局部變量保存約束屬性
private var bottomViewConsT: Constraint?
// 展示 view 時(shí)更新底部約束
bottomViewConsT?.update(offset: -tmpBottomConsH)
UIView.animate(withDuration: kTime.duration, animations: {[weak self] in
self?.layoutIfNeeded()
}) { (_) in
}
// 設(shè)置約束
bottomView.snp.makeConstraints { (make) in
make.left.right.equalTo(self).offset(0)
make.height.equalTo(frame.height * 0.35)
bottomViewConsT = make.top.equalTo(self.snp.bottom).offset(0).constraint
}
// 隱藏 view 時(shí)更新底部約束
bottomViewConsT?.update(offset: 0)
UIView.animate(withDuration: 0.1, animations: { [weak self] in
self?.layoutIfNeeded()
}) { [weak self] (_) in
self?.removeFromSuperview()
}
其實(shí)可以改為:
// 展示 view 時(shí)更新底部約束
bottomView.snp.updateConstraints { (make) in
make.top.equalTo(self.snp.bottom).inset(0)
}
// 設(shè)置約束
bottomView.snp.makeConstraints { (make) in
make.left.right.equalTo(self).offset(0)
make.height.equalTo(frame.height * 0.35)
bottomViewConsT = make.top.equalTo(self.snp.bottom).offset(0).constraint
}
// ……
這么做的好處就是語法更簡(jiǎn)潔一致坦弟,讓約束表現(xiàn)得更像是 view 的屬性。但缺點(diǎn)也很明顯嚼锄,只能更新 constant减拭。
暫時(shí)就這些吧(^_^)~~~