iOS - AutoLayout -1
1、AutoLayout
自動(dòng)布局(AutoLayout)是iOS6引入的關(guān)系布局,實(shí)現(xiàn)動(dòng)態(tài)位置和多視圖關(guān)系的布局方式,是對(duì)frame布局和AutoresizingMask的不足進(jìn)行補(bǔ)充的一種方式,現(xiàn)在已經(jīng)成為主流的布局方案,由于原始創(chuàng)建方式比較復(fù)雜,可以使用優(yōu)秀的第三方框架方便創(chuàng)建約束(Swift: SnapKit, Objective-C: Masonary)。
AutoLayout,是一個(gè)基于約束,動(dòng)態(tài)計(jì)算視圖大小和位置的庫(kù),以布局引擎系統(tǒng)Layout Engine為核心,采用了 Cassowary布局算法,Layout Engine統(tǒng)一管理了布局的創(chuàng)建、更新、銷(xiāo)毀,將視圖的約束、優(yōu)先級(jí)、固定大小通過(guò)計(jì)算轉(zhuǎn)換成最終的大小和位置。
在Layout Engine中,每當(dāng)約束發(fā)生變化,會(huì)重新計(jì)算布局,獲取到布局后調(diào)用superview.setNeedLayout(),然后觸發(fā)Deffered Layout Pass做容錯(cuò)處理,然后Layout Engine會(huì)從上到下調(diào)用layoutSubviews()來(lái)確定各子視圖的位置(通過(guò)Cassowary算法計(jì)算),算出來(lái)后將子視圖的frame從Layout Engine里拷貝出來(lái),然后進(jìn)行繪制、渲染,得到我們眼中看到的UI效果。
cassowary算法
1997年,一個(gè)名叫 Cassowary 的布局算法解決了用戶(hù)界面的布局問(wèn)題,它通過(guò)將布局問(wèn)題抽象成線(xiàn)性等式和不等式約束來(lái)進(jìn)行求解。
Cassowary能夠有效解析線(xiàn)性等式系統(tǒng)和線(xiàn)性不等式系統(tǒng),用來(lái)表示用戶(hù)界面中那些相等關(guān)系和不等關(guān)系?;诖?,Cassowary開(kāi)發(fā)了一種規(guī)則系統(tǒng),通過(guò)約束來(lái)描述視圖間的關(guān)系。約束就是規(guī)則,這個(gè)規(guī)則能夠表示出一個(gè)視圖相對(duì)于另外一個(gè)視圖的位置。
由于Cassowary算法讓視圖位置可以按照一種簡(jiǎn)單的布局思路來(lái)寫(xiě),這些簡(jiǎn)單的相對(duì)位置描述可以在運(yùn)行時(shí)動(dòng)態(tài)的計(jì)算出視圖具體的位置。視圖位置寫(xiě)法簡(jiǎn)化,界面相關(guān)代碼也就更易于維護(hù)。蘋(píng)果公司也是看中了這一點(diǎn),將其引入了自己的系統(tǒng)中。
AutoLayout的性能
Auto Layout 進(jìn)行布局時(shí),可以指定一系列的約束,比如視圖的高度、寬度等等。而每一個(gè)約束其實(shí)都是一個(gè)簡(jiǎn)單的線(xiàn)性等式或不等式,整個(gè)界面上的所有約束在一起就明確地(沒(méi)有沖突)定義了整個(gè)系統(tǒng)的布局。
在涉及沖突發(fā)生時(shí),AutoLayout 盡量滿(mǎn)足最多并且優(yōu)先級(jí)最高的約束, break一些優(yōu)先級(jí)低的約束
在iOS12之前,AutoLayout在處理多層級(jí)嵌套時(shí),開(kāi)銷(xiāo)呈指數(shù)級(jí)躍增,但是從iOS12開(kāi)始,蘋(píng)果補(bǔ)齊了這一漏洞,所以在iOS12及以后,我們就開(kāi)始放心的使用AutoLayout,更多關(guān)于AutoLayout的性能問(wèn)題及解決方法,請(qǐng)查看WWDC2018-202
AutoLayout布局原理和語(yǔ)法
AutoLayout是通過(guò)約束來(lái)實(shí)現(xiàn)布局的。一個(gè)view一旦使用了AutoLayout約束,那么它的frame將永遠(yuǎn)都是0
在使用AutoLayout之前需要兩個(gè)準(zhǔn)備工作
- 設(shè)置translatesAutoresizingMaskIntoConstraints為false
- 如果是viewControl則AutoLayout適配寫(xiě)在
- (void)updateViewConstraints中。
如果是view則AutoLayout適配寫(xiě)在 - (void)updateConstraints中。實(shí)際上,這也正是AutoLayout好處之一,可以集中將一個(gè)controller和view的適配在一個(gè)方法中。
參數(shù)
let constraint = [NSLayoutConstraint (item: <#T##Any#>, attribute: <#T##NSLayoutConstraint.Attribute#>, relatedBy: <#T##NSLayoutConstraint.Relation#>, toItem: <#T##Any?#>, attribute: <#T##NSLayoutConstraint.Attribute#>, multiplier: <#T##CGFloat#>, constant: <#T##CGFloat#>)]
創(chuàng)建一個(gè)AutoLayout需要七個(gè)參數(shù),他們分別是
(1)Item:被約束對(duì)象
(2)第一個(gè)attribute:被約束對(duì)象的關(guān)系
(3)relatedBy:約束描述
(4)toItem:約束源
(5)第二個(gè)attribute:約束源的關(guān)系
(6)multiplier:約束系數(shù)
(7)constant:約束常數(shù)
- 其中 attributebute 對(duì)應(yīng)的屬性如下
public enum Attribute : Int {
case left = 1
case right = 2
case top = 3
case bottom = 4
case leading = 5
case trailing = 6
case width = 7
case height = 8
case centerX = 9
case centerY = 10
case lastBaseline = 11
@available(iOS 8.0, *)
case firstBaseline = 12
@available(iOS 8.0, *)
case leftMargin = 13
@available(iOS 8.0, *)
case rightMargin = 14
@available(iOS 8.0, *)
case topMargin = 15
@available(iOS 8.0, *)
case bottomMargin = 16
@available(iOS 8.0, *)
case leadingMargin = 17
@available(iOS 8.0, *)
case trailingMargin = 18
@available(iOS 8.0, *)
case centerXWithinMargins = 19
@available(iOS 8.0, *)
case centerYWithinMargins = 20
case notAnAttribute = 0
}
其中l(wèi)eading 、trailing 是表示前、后,
left、right 表示左右,某種意義上leading == left,trailing == right,但是當(dāng)旋轉(zhuǎn)的時(shí)候會(huì)出現(xiàn)一些問(wèn)題,所有建議大家使用 leading 、trailing
- relatedBy 對(duì)應(yīng)的屬性如下
public enum Relation : Int {
case lessThanOrEqual = -1
case equal = 0
case greaterThanOrEqual = 1
}
約束描述主要就是<= 、==、 >= 主要是用于不確定大小和坐標(biāo)的約束
- 約束系數(shù)multiplier和約束常數(shù)constant主要是計(jì)算約束關(guān)系最終結(jié)果的,遵循公式"view1.attr1 = view2.attr2 * multiplier + constant"
想準(zhǔn)確的將一個(gè)View動(dòng)態(tài)布局,有時(shí)候往往需要設(shè)置好幾個(gè)約束來(lái)定位view的位置,所以這種代碼寫(xiě)起來(lái)往往比設(shè)置frame更加的冗長(zhǎng),所以就有了AutoLayout的出現(xiàn)。
未完待續(xù)。。。