一罐柳、前言
說到Swift中對(duì)AutoLayout的封裝王者無疑是SnapKit,它簡(jiǎn)單方便的調(diào)用無疑深得人心拂到。筆者今天要講的是利用Swift的特性對(duì)AutoLayout進(jìn)行簡(jiǎn)單的封裝帅刊。相比較SnapKit而言走芋,它的使用不能說更簡(jiǎn)單方便全闷,但實(shí)現(xiàn)可以說是一目了然叉寂,也算是對(duì)AutoLayout的介紹。下面將會(huì)講封裝的思路以及使用介紹总珠。
二屏鳍、JYAutoLayout的封裝思路
如上面演示圖的所示,所有橙色 和 白色的View的布局均相對(duì)于灰色的大View 而每個(gè)view的布局只需要短短的一行代碼:
UIedgeView(htrBtn).left(centerBtn,c:8).alignTop(centerBtn).size(btnSize).end()
2.1NSLayoutConstraint約束創(chuàng)建
convenience init(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute, multiplier: CGFloat, constant c: CGFloat)
這是一條約束的創(chuàng)建局服,它的約束關(guān)系是 view1.attr1 < = > view2.attr2 * multiplier + c
所以我們可以看到?jīng)Q定一個(gè)View1的某條約束所需的參數(shù)有:
var View2 : UIView? 相對(duì)于哪個(gè)view 即view2
var Attribute1 : NSLayoutAttribute? view1 的NSLayoutAttribute
var Attribute2 : NSLayoutAttribute? view2 的NSLayoutAttribute
var Multiplier : CGFloat? 比例系數(shù)
var Equal = NSLayoutRelation.Equal 大于 等于 小于
var offset : CGFloat 偏移
var priority : UILayoutPriority 當(dāng)然還有當(dāng)前約束的優(yōu)先級(jí)
2.2NSLayoutAttribute 包含有
case Left //左側(cè)
case Right //右側(cè)
case Top //上方
case Bottom //下方
case Leading //首部
case Trailing //尾部
case Width //寬度
case Height //高度
case CenterX //X軸中心
case CenterY //Y軸中心
case Baseline //文本底標(biāo)線
case NotAnAttribute //沒有屬性
在iOS8.0下又多了 一些邊界屬性
case LeftMargin
case RightMargin
case TopMargin
case BottomMargin
case LeadingMargin
case TrailingMargin
case CenterXWithinMargins
case CenterYWithinMargins
注:Left/Right 和 Leading/Trailing的區(qū)別是Left/Right永遠(yuǎn)是指左右钓瞭,而Leading/Trailing在某些從右至左習(xí)慣的地區(qū)會(huì)變成,leading是右邊腌逢,trailing是左邊降淮。
2.3簡(jiǎn)化封裝
以view的上邊為例我們可以提供下面一個(gè)方法來表示一條約束參數(shù)
private func top(v:UIView! , c : CGFloat , a : NSLayoutAttribute = NSLayoutAttribute.Bottom , m : CGFloat = 1.0 , e : NSLayoutRelation = NSLayoutRelation.Equal, p : UILayoutPriority = UILayoutPriorityDefaultHigh) -> UIedgeView {
}
view的top 與 v 的 a * m + c 當(dāng)然還有優(yōu)先級(jí)
swift有個(gè)非常好的地方,那就是只要設(shè)置了默認(rèn)參數(shù)就可以不用傳該參數(shù)搏讶,而在我們實(shí)際使用中 一般都是 等于 而比例細(xì)數(shù)也基本 是1.0佳鳖,所以通常 只要設(shè)置 v(view)c (偏移) a(對(duì)應(yīng)的邊)即可,而優(yōu)先級(jí)也基本不使用媒惕。
又考慮到 top 對(duì) top 與 top 對(duì) Bottom 是極為常見的所以又以方法名來區(qū)分 以 alignTop方法來表示 top 對(duì) top關(guān)系 而 top方法默認(rèn)表示 top 對(duì) Bottom關(guān)系 當(dāng)然top方法仍可以傳入NSLayoutAttribute參數(shù)系吩,這樣%90的情況下我們只需要設(shè)置兩個(gè)參數(shù) view 與 c 就可以描述一條參數(shù)。如: htrBtn.left(centerBtn,c:8)
同理對(duì) Bottom Right Left Width Height CenterX CenterY做了處理妒蔚。
2.4鏈?zhǔn)骄幊痰膶?shí)現(xiàn)
swift的方法調(diào)用都是點(diǎn)語(yǔ)法穿挨,再也不像OC那樣需要[],我們只需要在一個(gè)方法結(jié)束時(shí)返回self 就可以無限調(diào)用
@discardableResult func top(_ v: UIView! , c: CGFloat = 0 , a: NSLayoutAttribute = NSLayoutAttribute.bottom , m: CGFloat = 1.0 , e: NSLayoutRelation = NSLayoutRelation.equal, p: UILayoutPriority = UILayoutPriorityDefaultHigh) -> UIedgeView {
let layout = JYlayout(v: v, c: c, a1:NSLayoutAttribute.top , a2: a, m: m, e: e, p: p)
dict .setValue(layout, forKey: ffTop)
return self
}
2.5約束的添加 end() remake() update()
對(duì)于這么一個(gè)布局 htrBtn.left(centerBtn,c:8).alignTop(centerBtn).size(btnSize) 都是約束的準(zhǔn)備只是將約束所需要的參數(shù)保存到了UIedgeView這么一個(gè)對(duì)象中
而 end() remake() update() 才是添加相應(yīng)的約束
end() 什么都不管只管添加約束
remake() 會(huì)將之前的約束全部刪除,重新添加
update() 會(huì)根據(jù)當(dāng)前代碼所設(shè)計(jì)到的約束肴盏,而刪除對(duì)應(yīng)約束科盛,比如 btn.centerX(self).size(100, h: 100).update() 它涉及到了 centerX Width Height 的約束那么它會(huì)將之前添加的關(guān)于 centerX Width Height 的所有約束刪除然后添加。
注意:1.remake() update() 刪除約束使用的是以下方法:
public func removeConstraint(constraint: NSLayoutConstraint) // This method will be deprecated in a future release and should be avoided. Instead set NSLayoutConstraint's active property to NO.
這個(gè)方法將會(huì)在將來的版本中被棄用,應(yīng)該避免菜皂。蘋果也不太建議刪除約束再添加贞绵,如果有約束改變應(yīng)當(dāng)記錄約束直接修改,可以參考Demo中的AnimDemoView1恍飘,或者添加多個(gè)約束使用修改優(yōu)先級(jí)來達(dá)到改變的目的榨崩,可以參考Demo中的AnimDemoView2
2.不要使用 btn.centerX(self).centerX(view2).end() 這種寫法是錯(cuò)誤的,有效約束只會(huì)是centerX(view2)章母。如有需要應(yīng)當(dāng)如下:
btn.makeConstraint { (make) in
make.centerX(reference1,p:priorityMedium).end()
make.centerX(reference2,p:priorityHigh).end()
}
7.提供的方法說明
top 默認(rèn) top 對(duì) bottom
alignTop top 對(duì) top
left 默認(rèn) left 對(duì) right
alignLeft left 對(duì) left
bottom 默認(rèn) bottom 對(duì) top
alignBottom bottom 對(duì) bottom
right 默認(rèn) right 對(duì) left
alignRight right 對(duì) right
centerX 默認(rèn) centerX 對(duì) centerX
centerY 默認(rèn) centerY 對(duì) centerY
center 默認(rèn) centerX 對(duì) centerX centerY 對(duì) centerY
height 有對(duì)view 的 height 也有提供 數(shù)字 50
width 有對(duì)view 的 width 也有提供 數(shù)字 50
size 有對(duì)view 的 width height 也有提供 CGsize
方法的參數(shù)描述
@discardableResult func top(_ v: UIView! , c: CGFloat = 0 , a: NSLayoutAttribute = NSLayoutAttribute.bottom , m: CGFloat = 1.0 , e: NSLayoutRelation = NSLayoutRelation.equal, p: UILayoutPriority = UILayoutPriorityDefaultHigh) -> UIedgeView {
let layout = JYlayout(v: v, c: c, a1:NSLayoutAttribute.top , a2: a, m: m, e: e, p: p)
dict .setValue(layout, forKey: ffTop)
return self
}
v :參照的view
c : 偏移
m : 比例系數(shù)
a : 參照view的NSLayoutAttribute
e : NSLayoutRelation.Equal 大于 等于 小于
p : 優(yōu)先級(jí)
關(guān)于優(yōu)先級(jí)定義:
public let priorityHighTop = (UILayoutPriority)(UILayoutPriorityDefaultHigh + 1);
public let priorityHigh = UILayoutPriorityDefaultHigh;
public let priorityMedium = (UILayoutPriority)(500);
public let priorityLow = UILayoutPriorityDefaultLow;
public let priorityRequired = UILayoutPriorityRequired;
public let priorityFittingSizeLevel = UILayoutPriorityFittingSizeLevel;
如果還需要 Baseline 等相關(guān)關(guān)系可自行封裝母蛛,都是體力活
三、結(jié)尾
JYAutoLayout是筆者在Swift2 時(shí)代的一個(gè)練手產(chǎn)物乳怎,利用了Swift點(diǎn)語(yǔ)法調(diào)用以及參數(shù)可預(yù)設(shè)的特性對(duì)AutoLayout的封裝彩郊,使用也是簡(jiǎn)單方便。SnapKit雖然使用簡(jiǎn)單蚪缀,但在我看來它封裝的過于復(fù)雜了焦辅,帶來的收益(簡(jiǎn)單調(diào)用)完全可以用更方便的方式封裝。相信大家在升級(jí)到Xcode8時(shí)看到SnapKit爆紅時(shí)有多么萌比椿胯,我們也只能等待作者更新筷登。與其依賴別人,不如依賴自己哩盲,JYAutoLayout的封裝相當(dāng)簡(jiǎn)單相信一個(gè)對(duì)AutoLayout有所了解的同學(xué)在看完筆者的簡(jiǎn)單說明后自己就可以寫出來了前方,在之上擴(kuò)展優(yōu)化更不在話下。
如果我的文章對(duì)你有幫助或者給了你一些啟發(fā)廉油,希望你能在github給個(gè)小星星惠险,如果你在使用過程中遇到了Bug請(qǐng)留言反饋,我會(huì)及時(shí)解決抒线。歡迎轉(zhuǎn)載(在文章開頭標(biāo)明來源即可)班巩。