Auto Layout詳解

Auto Layout前世今生

Auto Layout 拴清,是蘋果公司提供的一個(gè)基于約束布局,動(dòng)態(tài)計(jì)算視圖大小和位置的庫(kù)俱笛,并且已經(jīng)集成到了 Xcode 開發(fā)環(huán)境里朵纷。

在引入 Auto Layout 這種自動(dòng)布局方式之前,iOS 開發(fā)都是采用手動(dòng)布局的方式晤郑。而手動(dòng)布局的方式,原始落后、界面開發(fā)維護(hù)效率低造寝,對(duì)從事過前端開發(fā)的人來(lái)說更是難以適應(yīng)磕洪。所以,蘋果需要提供更好的界面引擎來(lái)提升開發(fā)者的體驗(yàn)诫龙,Auto Layout 隨之出現(xiàn)析显。但是在推出來(lái)之后,響應(yīng)卻平平签赃,其原因就在于對(duì)其性能的擔(dān)憂谷异。即使后來(lái),蘋果公司推出了在 Auto Layout 基礎(chǔ)上模仿前端 Flexbox 布局思路的 UIStackView 工具锦聊,提高了開發(fā)體驗(yàn)和效率歹嘹,也無(wú)法解除開發(fā)者們對(duì)其性能的顧慮。

iOS 12 將大幅提高 Auto Layout 性能孔庭,使滑動(dòng)達(dá)到滿幀尺上。這不得不說Cassowary 算法。

Cassowary布局算法

Cassowary 能夠有效解析線性等式系統(tǒng)和線性不等式系統(tǒng),用來(lái)表示用戶界面中那些相等關(guān)系和不等關(guān)系圆到≡跖祝基于此,Cassowary 開發(fā)了一種規(guī)則系統(tǒng)芽淡,通過約束來(lái)描視圖間的關(guān)系马绝。約束就是規(guī)則,這個(gè)規(guī)則能夠表示出一個(gè)視圖相對(duì)于另一個(gè)視圖的位置挣菲。由于 Cassowary 算法讓視圖位置可以按照一種簡(jiǎn)單的布局思路來(lái)寫富稻,這些簡(jiǎn)單的相對(duì)位置描述可以在運(yùn)行時(shí)動(dòng)態(tài)地計(jì)算出視圖具體的位置。視圖位置的寫法簡(jiǎn)化了己单,界面相關(guān)代碼也就更易于維于維護(hù)唉窃。蘋果公司也是看重了這一點(diǎn),將其引入到了自己的系統(tǒng)中纹笼。由于 Cassowary 算法本身的先進(jìn)性纹份,更多的開發(fā)者將Cassowary 運(yùn)用到了各個(gè)開發(fā)語(yǔ)言中,比如 JavaScript廷痘、.NET蔓涧、Java、Smalltalk笋额、C++都有對(duì)應(yīng)的庫(kù)元暴。

Auto Layout 的生命周期

Auto Layout 不只有布局算法 Cassowary,還包含了布局在運(yùn)行時(shí)的生命周期等一整套布局引擎系統(tǒng)兄猩,用來(lái)統(tǒng)一管理布局的創(chuàng)建茉盏、更新和銷毀鉴未。了解 Auto Layout 的生命周期,是理解它的性能相關(guān)話題的基礎(chǔ)鸠姨。

這一整套布局引擎系統(tǒng)叫作 Layout Engine 铜秆,是 Auto Layout 的核心,主導(dǎo)著整個(gè)界面布局讶迁。

每個(gè)視圖在得到自己的布局之前连茧,Layout Engine 會(huì)會(huì)將視圖、約束巍糯、優(yōu)先級(jí)啸驯、固定大小通過計(jì)算轉(zhuǎn)換成最終的大小和位置。在 Layout Engine 里祟峦,每當(dāng)約束發(fā)生變化罚斗,就會(huì)觸發(fā) Deffered Layout Pass,完成后進(jìn)入監(jiān)聽約束變化的狀態(tài)搀愧。當(dāng)再次監(jiān)聽到約束變化惰聂,即進(jìn)入下一輪循環(huán)中。整個(gè)過程如下圖所示:

圖1:Layout Engine 界面布局過程

圖中咱筛, Constraints Change 表示的就是約束變化搓幌,添加、刪除視圖時(shí)會(huì)觸發(fā)約束變化迅箩。Activating 或 Deactivating溉愁,設(shè)置 Constant 或 Priority 時(shí)也會(huì)觸發(fā)約束變化。Layout Engine 在碰到約束變化后會(huì)重新計(jì)算布局饲趋,獲取到布局后調(diào)用 superview.setNeedLayout()拐揭,然后進(jìn)入 Deferred Layout Pass。

Deferred Layout Pass 的主要作用是做容錯(cuò)錯(cuò)處理奕塑。如果有些視圖在更新約束時(shí)沒有確定或缺失布局聲明的話堂污,會(huì)先在這里做容錯(cuò)處理。

接下來(lái)龄砰,Layout Engine 會(huì)從上到下調(diào)用layoutSubviews() 盟猖,通過 Cassowary算法計(jì)算各個(gè)子視圖的位置,算出來(lái)后將子視圖的 frame 從Layout Engine 里拷貝出來(lái)换棚。

在這之后的處理式镐,就和手寫布局的繪制、渲染過程一樣了固蚤。所以娘汞,使用 Auto Layout 和手寫布局的區(qū)別,就是多了布局上的這個(gè)計(jì)算過程夕玩。

Auto Layout 性能問題

Auto Layout 在 iOS 12 中優(yōu)化后你弦,它的性能得到了極大的提升惊豺,已經(jīng)基本和手寫布局一樣可以達(dá)到性能隨著視圖嵌套的數(shù)量呈線性增長(zhǎng)了。而在此之前的 Auto Layout鳖目,視圖嵌套的數(shù)量對(duì)對(duì)性能的影響是呈指數(shù)級(jí)增長(zhǎng)的扮叨。使用 Auto Layout 一定要注意多使用 Compression Resistance Priority 和 Hugging Priority缤弦,利用優(yōu)先級(jí)的設(shè)置领迈,讓布局更加靈活,代碼更少碍沐,更易于維護(hù)狸捅。

圖2: Auto Layout 在 iOS 12 中優(yōu)化后的表現(xiàn)

AutoLayout常見的問題

(1)幾個(gè)更新方法的區(qū)別

  • setNeedsLayout:告知頁(yè)面需要更新,但是不會(huì)立刻開始更新累提。執(zhí)行后會(huì)立刻調(diào)用layoutSubviews尘喝。
  • layoutIfNeeded:如果有需要刷新的標(biāo)記,立即調(diào)用layoutSubviews進(jìn)行布局斋陪;如果沒有標(biāo)記朽褪,不會(huì)調(diào)用layoutSubviews。如果希望立刻生成新的frame需要調(diào)用此方法无虚,利用這點(diǎn)一般布局動(dòng)畫可以在更新布局后直接使用這個(gè)方法讓動(dòng)畫生效缔赠。
  • layoutSubviews:對(duì)subviews進(jìn)行布局,不能主動(dòng)調(diào)用友题,需要的時(shí)候在子類重寫嗤堰,系統(tǒng)會(huì)在合適的時(shí)候自動(dòng)調(diào)用。
  • 注意 : 如果要立即刷新frame度宦,要先調(diào)用setNeedsLayout()踢匣,把標(biāo)記設(shè)為需要布局,然后馬上調(diào)用layoutIfNeeded()戈抄,實(shí)現(xiàn)布局离唬。
  • setNeedsUpdateConstraints:告知需要更新約束,但是不會(huì)立刻開始
  • updateConstraintsIfNeeded:告知立刻更新約束
  • updateConstraints:系統(tǒng)更新約束

(2)系統(tǒng)調(diào)用layoutSubviews的時(shí)機(jī)

  • init初始化不會(huì)觸發(fā)layoutSubviews划鸽,但是使用initWithFrame進(jìn)行初始化且rect不為zero時(shí)输莺,會(huì)調(diào)用layoutSubviews。
  • addSubview的時(shí)候會(huì)觸發(fā)系統(tǒng)調(diào)用layoutSubviews漾稀。
  • 當(dāng)view的frame發(fā)生改變的時(shí)候觸發(fā)layoutSubviews模闲。
  • 滾動(dòng)一個(gè)UIScrollView會(huì)觸發(fā)layoutSubviews。
  • 旋轉(zhuǎn)Screen會(huì)觸發(fā)父UIView上的layoutSubviews事件崭捍。
  • 改變一個(gè)UIView大小的時(shí)候也會(huì)調(diào)用父UIView上的layoutSubviews事件尸折。

具體細(xì)節(jié)可以參考:http://www.code4app.com/blog-822415-3151.html

(3)什么時(shí)候使用frame布局,什么時(shí)候選用Auto Layout布局

簡(jiǎn)單的 UI 使用 Auto Layout 殷蛇,復(fù)雜的 UI 使用 frame实夹。原因如下:

  • 從代碼量上來(lái)看橄浓,兩種布局方式相差不大。有時(shí)候發(fā)現(xiàn)復(fù)雜的 UI 使用 Auto Layout 的話亮航,代碼量反而會(huì)變多荸实,因?yàn)閺?fù)雜的 UI 往往會(huì)有復(fù)雜的邏輯,比如根據(jù)數(shù)據(jù)的不同缴淋,部分 UI 的顯示會(huì)有變動(dòng)(比如某個(gè)子視圖隱藏與顯示准给, 會(huì)影響到其它視圖的布局)。
  • 固定的UI簡(jiǎn)單的布局重抖,這種情況下使用 Auto Layout 還是挺方便的露氮,具有快速、方便钟沛、簡(jiǎn)潔的布局效果畔规。
  • 動(dòng)態(tài)復(fù)雜的 UI 布局,這種情況下使用 Auto Layout 來(lái)布局恨统,感覺就不合適叁扫。因?yàn)椴还苁?frame 還是 Auto Layout,都需要去計(jì)算高度畜埋,Auto Layout通過 Cassowary 算法計(jì)算各個(gè)子視圖的位置莫绣,算出來(lái)后將子視圖的 frame 從 Layout Engine 里拷貝出來(lái);而frame布局由捎,則可以快速的通過事先約定的布局計(jì)算出相應(yīng)的frame兔综,再進(jìn)行相應(yīng)的繪制、渲染狞玛。這種情況下软驰,直接使用 frame 會(huì)比較精簡(jiǎn)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末心肪,一起剝皮案震驚了整個(gè)濱河市锭亏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌硬鞍,老刑警劉巖慧瘤,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異固该,居然都是意外死亡锅减,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門伐坏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)怔匣,“玉大人,你說我怎么就攤上這事桦沉∶柯鳎” “怎么了金闽?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)剿骨。 經(jīng)常有香客問我代芜,道長(zhǎng),這世上最難降的妖魔是什么浓利? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任挤庇,我火速辦了婚禮,結(jié)果婚禮上荞膘,老公的妹妹穿的比我還像新娘罚随。我一直安慰自己,他們只是感情好羽资,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著遵班,像睡著了一般屠升。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上狭郑,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天腹暖,我揣著相機(jī)與錄音,去河邊找鬼翰萨。 笑死脏答,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的亩鬼。 我是一名探鬼主播殖告,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼雳锋!你這毒婦竟也來(lái)了黄绩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤玷过,失蹤者是張志新(化名)和其女友劉穎爽丹,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體辛蚊,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡粤蝎,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了袋马。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片初澎。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖飞蛹,靈堂內(nèi)的尸體忽然破棺而出谤狡,到底是詐尸還是另有隱情灸眼,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布墓懂,位于F島的核電站焰宣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捕仔。R本人自食惡果不足惜匕积,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望榜跌。 院中可真熱鬧闪唆,春花似錦、人聲如沸钓葫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)础浮。三九已至帆调,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間豆同,已是汗流浹背番刊。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留影锈,地道東北人芹务。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像鸭廷,于是被迫代替她去往敵國(guó)和親枣抱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容