再看SnapKit
連續兩個多月高強度的工作,每天幾乎加班到8點才下班,專案在今天上午終於是提交到 App Store 了。整個人瞬時如釋重負,但卻有種空虛感,不知道做什麼了。再看下SnapKit吧。發現之前一直認為就那麼用來設定約束即可,沒留意到的地方還挺多。下面分別概述下。
一、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)
}
其實 offset 使用的是絕對值,尤其是設定右、下約束的時候,子控制元件相對於父控制元件都需要加-號。這一點使用久了,和蘋果的 xib 比起來,或多或少覺得有點不太合理。其實該框架是有 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,之前的程式碼就可以簡化成這樣(只是舉例):
make.top.equalTo(researchView.snp.bottom).offset(kHeight.d10)
make.left.equalTo(10)
make.right.equalToSuperview().inset(10)
make.bottom.equalTo(bottomView.snp.bottom)
}
總結下來就是:在描述 view 與 superview 關係時,應該使用 inset,而描述 view 與同一層級的其它 view 時,應該使用 offset。
二、ConstraintConstantTarget
在佈局 view 的時候,一般來說設計師都會給 content 一個統一的邊距,類似於 html 中的 padding,在構建約束時我們經常會把這個 padding 分散到各處。但事實上,將 padding 分散去處理是一件很糟糕的事情,程式碼不美觀是其次,最重要的是後期維護起來費時費力,更好的方式是使用已有的抽象 UIEdgeInsets。
在呼叫 equalTo, offset 或者 inset 傳入數值時,我們會發現傳入的引數型別實際上只有 ConstraintConstantTarget,這是一個協議,SnapKit 把它作為一個類簇在使用,通過一個方法將它轉化為 CGFloat 來作為 constraint 的 constant。
UIEdgeInsets 也遵循了這個協議,所以我們可以更加優雅地去處理邊距:
// 如果視覺稿中所有的頁面的左右邊距都遵循左右距離相同,該屬性可以改為全域性屬性。
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)
}
這樣,後期修改起來會很容易,程式碼也簡潔了很多。另外 CGPoint 和 CGSize 也遵循了這個協議,大家可以去研究下更多有趣的用法,例如 size.equalTo(20)。
三、修改約束儘量用 updateConstraints
如果要更新佈局約束,小弟之前的做法是仿照蘋果,用區域性變數來引用,然後更新。如下:
// 區域性變數儲存約束屬性
private var bottomViewConsT: Constraint?
// 展示 view 時更新底部約束
bottomViewConsT?.update(offset: -tmpBottomConsH)
UIView.animate(withDuration: kTime.duration, animations: {[weak self] in
self?.layoutIfNeeded()
}) { (_) in
}
// 設定約束
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 時更新底部約束
bottomViewConsT?.update(offset: 0)
UIView.animate(withDuration: 0.1, animations: { [weak self] in
self?.layoutIfNeeded()
}) { [weak self] (_) in
self?.removeFromSuperview()
}
其實可以改為:
// 展示 view 時更新底部約束
bottomView.snp.updateConstraints { (make) in
make.top.equalTo(self.snp.bottom).inset(0)
}
// 設定約束
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 的屬性。但缺點也很明顯,只能更新 constant。
暫時就這些吧(^_^)~~~
相關文章
- SnapKit入門教程APK
- SnapKit 最佳實踐APK
- SnapKit 中文文件翻譯APK
- SnapKit 原始碼解讀(二):DSLsAPK原始碼
- SnapKit 原始碼解讀(一):ExtensionsAPK原始碼
- [譯] 再看 Flask 視訊流Flask
- 再看JVM:垃圾回收那些事JVM
- 再看 Composer 自動載入原始碼原始碼
- 2021再看Deno(CDN for JavaScript modules的思考)JavaScript
- 金雞落幕,從《流浪地球》再看人工智慧人工智慧
- 從原始碼的角度再看 React JS 中的 setState原始碼ReactJS
- 從Vue.js原始碼角度再看資料繫結Vue.js原始碼
- BI報表用多了,就再看不了其他報表
- 再看rabbitmq的交換器和佇列的關係MQ佇列
- 從硬體級別再看可見性和有序性
- 成為MySQL DBA後,再看ORACLE資料庫(十三、物理備份)MySqlOracle資料庫
- MySQL alter table時執行innobackupex全備再看Seconds_Behind_MasterMySqlAST
- 成為MySQL DBA後,再看ORACLE資料庫(五、記憶體管理)MySqlOracle資料庫記憶體
- 成為MySQL DBA後,再看ORACLE資料庫(七、日誌體系)MySqlOracle資料庫
- 瞭解JavaScript中的Memoization以提高效能,再看React的應用JavaScriptReact
- 成為MySQL DBA後,再看ORACLE資料庫(二、監聽與連線)MySqlOracle資料庫
- 成為MySQL DBA後,再看ORACLE資料庫(一、安裝與啟動)MySqlOracle資料庫
- 一朝入夢,終生不醒:再看紅樓夢,也談石頭記
- 成為MySQL DBA後,再看ORACLE資料庫(八、程序、連線與會話)MySqlOracle資料庫會話
- 李開復創業9年再看世界:中美科技成平行宇宙,VC也要+AI創業AI
- 成為MySQL DBA後,再看ORACLE資料庫(六、邏輯儲存結構)MySqlOracle資料庫
- 這遊戲到底怎麼了? 一年後,再看《刺客信條奧德賽》遊戲
- 成為MySQL DBA後,再看ORACLE資料庫(十、事務與隔離級別)MySqlOracle資料庫
- 在“直播型遊戲”大火的今年,再看《人類:一敗塗地》帶來的經驗遊戲
- 成為MySQL DBA後,再看ORACLE資料庫(十四、統計資訊與執行計劃)MySqlOracle資料庫
- 東方證券:從組織及管理賦能出發再看社群團購(附下載)
- 【十年奮戰,一朝夢醒】6年後的歸來,再看職場與自身發展
- 深入淺出!阿里P7架構師帶你分析ArrayList集合原始碼,建議是先收藏再看!阿里架構原始碼
- 關於Redis分散式鎖這一篇應該是講的最好的了,先收藏起來再看!Redis分散式
- 一文讓你徹底會用物件儲存OSS的前端直傳,不懂就再看一遍!(bushi)物件前端
- 時隔多年,再看這款2D魂系、塞爾達like獨立遊戲仍有諸多精彩設計之處遊戲
- 從人類電子裝置散熱簡史,再看騰訊黑鯊遊戲手機3的“三明治”液冷散熱遊戲