前言
最近公司項目不忙, 在學swift, 雖然之前也了解過, 但是沒怎么寫, 所以基本上都忘光了, 作為一個程序員, 怎么能夠不追求新的藝術呢, 對, swift就是一門藝術, 一個禮拜左右的時間, 邊看邊練, 寫了三個文件
- 網絡請求(對URLSession的封裝)
- 圖片加載器(簡仿寫的SDWebImage)
- 自動布局(類似Massory的調用方法 基于->NSLayoutConst.....)
下面針對自動布局的簡單概述一下
功能沒有那么SnapKit那么強大, 對我而言, 夠用足矣
調用的方法如下
imageView.makeConstraint { (maker) in
maker.center.equalTo(self.view.cm_center)
maker.width.height.equalTo(self.view).multiplier(0.5)
}
button.makeConstraint { (maker) in
maker.centerX.equalTo(self.view)
maker.top.equalTo(imageView.cm_bottom).constant(30)
maker.height.equal(40)
maker.width.equalTo(imageView)
}
上面代碼的效果如下
差不多, 挺好的 , 嗯 , 很棒
當然了. 更新約束也有的, 就不演示了只不過是make換成了update 比較習慣了Massory的 所以就采用了相同的辦法
實現的Api基于分類(extension) 對UIView的extension
func makeConstraint(constraint: (FMConstraintMaker) -> ()) -> Void {
self.isUpdateConstraint = false //是否是更新布局的標識
constraint(FMConstraintMaker(currentView: self))
}
- FMConstraintMaker(生成FMCMAttributes一個)
- FMCMAttributes(保存要約束的屬性FMCMAttribute)
- FMCMACalculate(根據屬性, 加上判斷得出NSLayoutConstraint)
- FMCMATarget(相對誰的約束包含屬性)
- FMCMAttribute(枚舉類型 所有的屬性類型)
- FMCMRelation(枚舉類型 約束的關系類型)
- FMCMVRelation(枚舉類型 當前控件與目標的控件的關系)
舉個例子
button.makeConstraint { (maker) in
maker.left.right.top.bottom.equalTo(self.view) // 四邊約束緊靠view的四邊
}
// maker.left之后
// 其他的屬性都是一樣的 根據不同的屬性名傳入相應的約束類型, 返回一個FMCMAttributes
lazy var left: FMCMAttributes = {
return FMCMAttributes(attribute: .left, current: self.currentMakerView)
}()
// maker.left.right之后 .top.bottom 也是一樣的道理
/* 這里調用的就是FMCMAttributes的對象了 僅僅是將對應的
屬性名標記加入到數組里 留著給后面去生成對應的布局 */
lazy var right: FMCMAttributes = {
self.attributes.append(.right)
return self
}()
再然后就到了equalTo這個方法 這個根據傳進來的參數做判斷生成FMCMACalculate
@discardableResult //這個標識是忽略這個方法的返回值沒有調用的警告
func equalTo(_ target: Any) -> FMCMACalculate {
return self.toCalculate(target: target, relation: .Equal)
}
private func toCalculate(target: Any, relation: FMCMRelation) -> FMCMACalculate {
if let targetView = target as? UIView {
return FMCMACalculate(current: self, targetView: targetView, relation: relation)
}
if let targetAttr = target as? FMCMATarget {
return FMCMACalculate(current: self, target: targetAttr, relation: relation)
}
return FMCMACalculate(current: self, relation: relation)
}
根據上傳的傳入的參數判斷
// FMCMACalculate
init(current: FMCMAttributes, targetView: UIView?, relation: FMCMRelation) {
self.current = current // FMCMAttributes實例對象
self.targetView = targetView // 目標的控件
self.hasAttribute = false // 是否是帶有屬性的 如:self.view.cm_left
self.target = nil // 帶有屬性的目標
self.relation = relation // 約束的關系 相等大于小于
}
根據上面的代碼 到這里已經結束了
但是這并沒有去添加布局的代碼
添加布局的代碼在
var constant: (Float) -> Void {
return { (value) in
self.hasConstant = true
for attr in self.current.attributes {
self.setAttribute(attribute: attr, constant: value)
}
}
}
func setAttribute(attribute: FMCMAttribute, constant: Float) -> Void {
let cons: NSLayoutConstraint = self.layoutConstraint(attribute: attribute, constant: constant) // 根據屬性與constant生成一個NSLayoutConstraint作為
var change: UIView?
switch self.viewrelation() { // 獲取當前的控件與目標的控件的關系
case .FatherAndSon:
change = self.current.current
break
case .SonAndFather:
change = self.current.current.superview!
break
case .Equative:
change = self.current.current.superview!
break
case .BeMySelf:
change = self.current.current
break
default:
change = nil
break
}
if change != nil {
if self.current.current.isUpdateConstraint { // 更新約束
let consItems = change!.constraints
if consItems.count == 0 {
return
}
var changeCon: NSLayoutConstraint?
for con in consItems {
if con.firstItem as! NSObject == self.current.current && con.firstAttribute == attribute.ConstraintAttr() {
changeCon = con
break
} else {
continue
}
}
if changeCon != nil {// 如果找到舊的約束 就可以移除這個舊的約束 更新成當前最新的
change!.removeConstraint(changeCon!)
change!.addConstraint(cons)
}
} else { // 添加約束
change!.addConstraint(cons)
}
}
}
到這里已經差不多了 至于為什么沒有調用這個方法就去更新是因為在析構方法里加了一層判斷 當這個FMCMACalculate對象即將銷毀的時候 如果沒有去布局的 就去執(zhí)行布局
deinit {
if !self.hasConstant {
self.constant(0)
}
}
差不多就是這些了 想通了 實現起來還是挺簡單的
更多請看源文件
demo地址