原文鏈接
Auto Layout 伪嫁,是蘋果公司提供的一個基于約束布局薄辅,動態(tài)計算視圖大小和位置的庫,并且已經(jīng)集成到了 Xcode 開發(fā)環(huán)境里。
在引入 Auto Layout 這種自動布局方式之前,iOS 開發(fā)都是采用手動布局的方式。
而手動布局的方式璃诀,原始落后、界面開發(fā)維護(hù)效率低蔑匣,對從事過前端開發(fā)的人來說更是難以適應(yīng)劣欢。
所以,蘋果需要提供更好的界面引擎來提升開發(fā)者的體驗裁良,Auto Layout 隨之出現(xiàn)凿将。
蘋果公司早在 iOS 6 系統(tǒng)時就引入了 Auto Layout,但是直到現(xiàn)在還有很多開發(fā)者遲遲不愿使用 它趴久,其原因就在于對其性能的擔(dān)憂丸相。
即使后來,蘋果公司推出了在 Auto Layout 基礎(chǔ)上模仿前端 Flexbox 布局思路的 UIStackView 工具彼棍,提高了開發(fā)體驗和效率,也無法解除開發(fā)者們對其性能的顧慮膳算。
Auto Layout 到底是如何實現(xiàn)自動布局的座硕,這種布局算法真的會影響性能嗎?
Auto Layout 的來歷
- 1997 年涕蜂,Auto Layout 用到的布局算法 Cassowary 被發(fā)明了出來华匾;
- 2011 年,蘋果公司將 Cassowary 算法運用到了自家的布局引擎 Auto Layout 中。
Cassowary 能夠有效解析線性等式系統(tǒng)和線性不等式系統(tǒng)蜘拉,用來表示用戶界面中那些相等關(guān)系和不等關(guān)系萨西。基于此旭旭,Cassowary 開發(fā)了一種規(guī)則系統(tǒng)谎脯,通過約束來描述視圖間的關(guān)系。
約束就是規(guī)則持寄,這個規(guī)則能夠表示出一個視圖相對于另一個視圖的位置源梭。
由于 Cassowary 算法讓視圖位置可以按照一種簡單的布局思路來寫,這些簡單的相對位置描述可以在運行時動態(tài)地計算出視圖具體的位置稍味。視圖位置的寫法簡化了废麻,界面相關(guān)代碼也就更易于維護(hù)。蘋果公司也是看重了這一點模庐,將其引入到了自己的系統(tǒng)中烛愧。
由于 Cassowary 算法本身的先進(jìn)性,更多的開發(fā)者將 Cassowary 運用到了各個開發(fā)語言中掂碱,比如 JavaScript怜姿、.NET、Java顶吮、Smalltalk社牲、C++ 都有對應(yīng)的庫。
Auto Layout 的生命周期
Auto Layout 不只有布局算法 Cassowary悴了,還包含了布局在運行時的生命周期等一整套布局引擎系統(tǒng)搏恤,用來統(tǒng)一管理布局的創(chuàng)建、更新和銷毀湃交。了解 Auto Layout 的生命周期熟空,是理解它的性能相關(guān)話題的基礎(chǔ)。這樣搞莺,在遇到問題息罗,特別是性能問題時,我們才能從根兒上找到原因才沧,從而避免或改進(jìn)類似的問題迈喉。
這一整套布局引擎系統(tǒng)叫作 Layout Engine ,是 Auto Layout 的核心温圆,主導(dǎo)著整個界面布局挨摸。
每個視圖在得到自己的布局之前,Layout Engine 會將視圖岁歉、約束得运、優(yōu)先級、固定大小通過計算轉(zhuǎn)換成最終的大小和位置。在 Layout Engine 里熔掺,每當(dāng)約束發(fā)生變化饱搏,就會觸發(fā) Deffered Layout Pass , 完成后進(jìn)入監(jiān)聽約束變化的狀態(tài)置逻。當(dāng)再次監(jiān)聽到約束變化推沸,即進(jìn)入下一輪循環(huán)中。整個過程如下圖所示:
圖中诽偷,Constraints Change 表示的就是約束變化坤学,添加、刪除視圖時會觸發(fā)約束變化报慕。
Activating 或 Deactivating深浮,設(shè)置 Constant 或 Priority 時也會觸發(fā)約束變化。
Layout Engine 在碰到約束變化后會重新計算布局眠冈,獲取到布局后調(diào)用 superview.setNeedLayout()飞苇,然后進(jìn)入 Deferred Layout Pass。
Deferred Layout Pass 的主要作用是做容錯處理蜗顽。如果有些視圖在更新約束時沒有確定或缺失布局聲明的話布卡,會先在這里做容錯處理。
接下來雇盖,Layout Engine 會從上到下調(diào)用 layoutSubviews() 忿等,通過 Cassowary 算法計算各個子視圖的位置,算出來后將子視圖的 frame 從 Layout Engine 里拷貝出來崔挖。
在這之后的處理贸街,就和手寫布局的繪制、渲染過程一樣了狸相。所以薛匪,使用 Auto Layout 和手寫布局的區(qū)別,就是多了布局上的這個計算過程脓鹃。
Auto Layout 性能問題
iOS 12 之前逸尖,很多約束變化時都會重新創(chuàng)建一個計算引擎 NSISEnginer 將約束關(guān)系重新加進(jìn)來,然后重新計算瘸右。結(jié)果就是娇跟,涉及到的約束關(guān)系變多時,新的計算引擎需要重新計算太颤,最終導(dǎo)致計算量呈指數(shù)級增加逞频。
iOS12 之后的 Auto Layout 更多地利用了 Cassowary 算法的界面更新策略,使其真正完成了高效的界面線性策略計算栋齿。
使用 Auto Layout 一定要注意多使用 Compression Resistance Priority 和 Hugging Priority,利用優(yōu)先級的設(shè)置,讓布局更加靈活瓦堵,代碼更少基协,更易于維護(hù)。
那么菇用,明確了 iOS 12 使得 Auto Layout 具有了和手寫布局幾乎相同的高性能后澜驮,你是不是就可以放心地使用 Auto Layout 了呢?答案是肯定的惋鸥。
常見問題
- 幾個方法的區(qū)別
setNeedsLayout:告知頁面需要更新杂穷,但是不會立刻開始更新。
執(zhí)行后會立刻調(diào)用layoutSubviews卦绣。layoutIfNeeded:如果有需要刷新的標(biāo)記耐量,立即調(diào)用layoutSubviews進(jìn)行布局;
如果沒有標(biāo)記滤港,不會調(diào)用layoutSubviews廊蜒。
如果希望立刻生成新的frame需要調(diào)用此方法,
利用這點一般布局動畫可以在更新布局后直接使用這個方法讓動畫生效溅漾。layoutSubviews:對subviews進(jìn)行布局山叮,不能主動調(diào)用,需要的時候在子類重寫添履,系統(tǒng)會在合適的時候自動調(diào)用屁倔。
注意 : 如果要立即刷新frame,要先調(diào)用setNeedsLayout()暮胧,把標(biāo)記設(shè)為需要布局锐借,然后馬上調(diào)用layoutIfNeeded(),實現(xiàn)布局叔壤。setNeedsUpdateConstraints:告知需要更新約束瞎饲,但是不會立刻開始
updateConstraintsIfNeeded:告知立刻更新約束
updateConstraints:系統(tǒng)更新約束
- 系統(tǒng)調(diào)用layoutSubviews的時機
- init初始化不會觸發(fā)layoutSubviews,但是使用initWithFrame進(jìn)行初始化且rect不為zero時炼绘,會調(diào)用layoutSubviews嗅战。
- addSubview的時候會觸發(fā)系統(tǒng)調(diào)用layoutSubviews。
- 當(dāng)view的frame發(fā)生改變的時候觸發(fā)layoutSubviews俺亮。
- 滾動一個UIScrollView會觸發(fā)layoutSubviews驮捍。
- 旋轉(zhuǎn)Screen會觸發(fā)父UIView上的layoutSubviews事件。
- 改變一個UIView大小的時候也會調(diào)用父UIView上的layoutSubviews事件
- 什么時候使用frame布局脚曾,什么時候選用Auto Layout布局
簡而言之东且,簡單的 UI 使用 Auto Layout ,復(fù)雜的 UI 使用 frame本讥。
原因如下:
從代碼量上來看珊泳,兩種布局方式相差不大鲁冯。有時候發(fā)現(xiàn)復(fù)雜的 UI 使用 Auto Layout 的話,代碼量反而會變多色查,因為復(fù)雜的 UI 往往會有復(fù)雜的邏輯薯演,比如根據(jù)數(shù)據(jù)的不同,部分 UI 的顯示會有變動(比如某個子視圖隱藏與顯示秧了, 會影響到其它視圖的布局)跨扮。
固定的UI簡單的布局,這種情況下使用 Auto Layout 還是挺方便的验毡,具有快速衡创、方便、簡潔的布局效果晶通。
動態(tài)復(fù)雜的 UI 布局璃氢,這種情況下使用 Auto Layout 來布局,感覺就不合適录择。因為不管是 frame 還是 Auto Layout拔莱,都需要去計算高度,Auto Layout通過 Cassowary 算法計算各個子視圖的位置隘竭,算出來后將子視圖的 frame 從 Layout Engine 里拷貝出來塘秦;而frame布局,則可以快速的通過事先約定的布局計算出相應(yīng)的frame动看,再進(jìn)行相應(yīng)的繪制尊剔、渲染。這種情況下菱皆,直接使用 frame 會比較精簡须误。