WWDC之Mysteries of Auto Layout Part 2

本文為WWDC2015的Session 219 "Mysteries of Auto Layout Part2" 視頻筆記,其內(nèi)容主要涉及了約束的生命周期和,Autolayout調(diào)試兩大內(nèi)容,學(xué)習(xí)記錄了視頻內(nèi)容重要的知識內(nèi)容,歡迎一起探討研究.

資源

內(nèi)容

The Layout Cycle

layoutCycle.png

為了說明Layout Cycle,蘋果工程師給出了這樣以上這張圖,果然一圖勝千言.基于整個App的運(yùn)行循環(huán)過程中,布局界面上的視圖前,首先會進(jìn)行約束進(jìn)行更新和設(shè)置,然后將最終的布局信息延時地傳遞給視圖,讓視圖獲取到相關(guān)Frame的信息,進(jìn)行位置的尺寸的確定,然后回到主運(yùn)行循環(huán),等待約束再發(fā)生變化.

Constraints Change

  • 約束改變后Frame不會馬上變化
  • 重寫layoutSubviews要十分當(dāng)心

讓約束發(fā)生變化的方式主要由以下三種:
1.使用官方極力推薦的NSLayoutConstraint的``activedeactive`兩個類方法來激活,或無效指定約束.(拋棄掉add/remove約束的方式吧~原因可見Mysteries of Auto Layout Part1 16:27)
方法代碼如下:

    [NSLayoutConstraint activateConstraints:]
    [NSLayoutConstraint deactivateConstraints:]
    // 參數(shù)為NSLayoutConstraint對象的數(shù)組

2.修改約束等式的常量值,乘數(shù)因子或者優(yōu)先值.接觸過Autolayout我們應(yīng)該都知道給視圖設(shè)置約束時要滿足一個約束等式如下.(就當(dāng)你知道了,(╯﹏╰)b)

equal.png

當(dāng)Constant或者Multipler變化時,創(chuàng)建的約束等式也相應(yīng)改變,使得
Layout引擎重寫計算布局.
而對于優(yōu)先值Priority的改變,往往表現(xiàn)在兩個視圖間同一位置的約束,將根據(jù)優(yōu)先級高的計算布局屬性,除此之外還有具有instrinsic Content Size屬性的視圖間的contentCompressionResistance或者contentHug的競爭.

3.添加或移除視圖,視圖都沒,跟自己相關(guān)的約束當(dāng)然也沒有嘍.(╮(╯▽╰)╭)

當(dāng)約束改變后,Layout引擎就會重新計算新的布局,將布局內(nèi)容的舊值替換成新值,然后調(diào)用父視圖的setNeedsLayout.
而對于setNeedsLayout的描述,官方文檔給出了詳細(xì)說明.此方法只是對當(dāng)前約束變化了的視圖了標(biāo)記,只有等到下一個視圖更新周期時視圖才會真正響應(yīng)約束的變化而改變Frame.如果想要讓視圖快速地響應(yīng)約束的變化,則需要調(diào)用layoutIfNeeded.

Deferred Layout Pass

約束發(fā)生變化后,就進(jìn)入了延遲的布局信息傳遞過程.為什么說延時的呢?回想一下,我們操作約束變化時經(jīng)常通過設(shè)置動畫時間來放大對應(yīng)Frame的延時改變.在這個階段里,視圖更新所在視圖層次內(nèi)的所有約束,然后重新賦值Frame屬性.
更新視圖的約束,使用setNeedsUpdateConstraints 就表示著該視圖的約束需要更新,而具體的更新會在將來某一時刻進(jìn)行.其調(diào)用的時機(jī),蘋果工程師給了兩個情景:

  • 當(dāng)某約束在所在位置變化太慢時,使用update期間將更快的更新約束.
  • 當(dāng)視圖約束頻繁且多余的變化時,調(diào)用后只會執(zhí)行最后一次的更新變化.

響應(yīng)視圖布局約束變化后,就到了對視圖位置布局的最終設(shè)置,而這個過程則是視圖從上到下遍歷視圖層次,調(diào)用layoutSuviews(iOS)/layout(OSX),設(shè)置具體的內(nèi)部子視圖的Frame.而重寫該方法時,主講人多次提醒開發(fā)者需要十分注意重寫方法時內(nèi)部的操作.
重寫layoutSuviews方法時,其內(nèi)部的約束是不完整的,具體表現(xiàn)為有的子視圖已經(jīng)完成了布局,而有的子視圖正在或者還未進(jìn)行布局.為了保證方法的正確執(zhí)行,我們必須調(diào)用父類的layoutSuviews,不能在其內(nèi)部調(diào)用setNeedsUpdateConstraints(時機(jī)太晚了,已經(jīng)進(jìn)入了布局階段),并且不能隨意地更改約束,防止與其他視圖層次相關(guān)的約束的改變.

Interacting Legacy Layout (處理系統(tǒng)遺留的布局)

  1. 當(dāng)我們用代碼使用Autolayout給視圖添加約束時,要時刻留意將translatesAutoresizingMaskIntoConstraints`設(shè)為NO,否則添加完約束后就會出現(xiàn)一下約束警告日志.
    interactConstraint.png
    .這是由于系統(tǒng)默認(rèn)設(shè)置了Yes,給視圖添加的固定約束而與我們自己后添加的約束產(chǎn)生了沖突,導(dǎo)致不能同時滿足約束條件進(jìn)行布局.(IB里自動將此屬性值設(shè)置為No).
  2. 如果想要自己設(shè)置內(nèi)部視圖的Frame時,重寫layoutSuviews,在此方法里設(shè)置,切記不要忘記調(diào)用父類方法.

Constraint Creation

關(guān)于系統(tǒng)自帶API進(jìn)行約束的創(chuàng)建方式一直以來都被我們詬病,設(shè)個約束出要那么大坨代碼(差評~)...但如果了解使用VFL創(chuàng)建約束的話還是很優(yōu)雅的,只是實現(xiàn)的約束有所限制.而現(xiàn)在iOS9提供了新的約束創(chuàng)建方式,讓開發(fā)者可以更加明了,快速地創(chuàng)建約束.

constraintCreate.png

通過查看UIView的頭文件,可以看到viewanchor屬性都定義在一個名為UIViewLayoutConstraintCreationUIView分類中.

// NSLayoutXAxisAnchor 類型表示在X軸上的約束
leadingAnchor 
trailingAnchor
leftAnchor 
rightAnchor
centerXAnchor

// NSLayoutXAxisAnchor 類型表示在Y軸上的約束
topAnchor
bottomAnchor
centerYAnchor
firstBaselineAnchor
lastBaselineAnchor 

// NSLayoutDimension 類型表示尺寸相關(guān)的約束
widthAnchor 
heightAnchor

初次之外,新的NSLayoutAnchor類的文件里提供了一系列進(jìn)行相關(guān)視圖進(jìn)行約束設(shè)置的方法,這里就不一一介紹,可以Command + R進(jìn)行看看.

Constraining Negative Space

這里所提到的關(guān)于對多個視圖進(jìn)行等間距或者同時居中的情況下,以前的做法就是創(chuàng)建假的UIView僅僅為提供約束來達(dá)成目的,而現(xiàn)在有了UILayoutGuide對象其表示著一個可以使用Autolayout的布局矩形區(qū)域,可以通過視圖的分類方法addLayoutGuide添加guide,來充當(dāng)之前僅僅提供約束的假視圖,作用于Autolayout.具體的話就舉一個實現(xiàn)讓三個按鈕等間距排列,結(jié)合代碼和圖應(yīng)該能剛好理解點.

Screen Shot 2015-12-12 at 10.31.31 PM.png

    //UIButton *saveButton;
    //UIButton *cancelButton;
    //UIButton *clearButton;
    
    UILayoutGuide *space1 = [[UILayoutGuide alloc]init];
    [saveButton addLayoutGuide:space1];
    UILayoutGuide *space2 = [[UILayoutGuide alloc]init];
    [cancelButton addLayoutGuide:space2];

    NSLayoutConstraint *spaceConstraint = [space1.widthAnchor constraintEqualToAnchor:space2.widthAnchor];
    NSLayoutConstraint *constraintOne = [saveButton.rightAnchor constraintEqualToAnchor: space1.leftAnchor];
    NSLayoutConstraint *constraintTow = [cancelButton.leftAnchor constraintEqualToAnchor:space1.rightAnchor];
    NSLayoutConstraint *constraintThree = [cancelButton.rightAnchor constraintEqualToAnchor:space2.leftAnchor];
    NSLayoutConstraint *constraintFour = [clearButton.leftAnchor constraintEqualToAnchor:space2.rightAnchor];
    
    [NSLayoutConstraint activateConstraints:@[spaceConstraint, constraintOne, constraintTow, constraintThree, constraintFour]];

Unsatisfiable Constraints

想要了解Unsatisfiable的具體的相關(guān)約束以及關(guān)聯(lián)對象,就必須要理解輸出的約束警告日志.

understandLog3.png

現(xiàn)在允許給約束或者視圖添加約束標(biāo)識符identifier字符串屬性,將會在日志輸出中顯示,極大讓日志內(nèi)容更加清晰,讓開發(fā)者快速找到存在問題的約束和視圖.

Resolving Ambiguity

出現(xiàn)Ambigous Layout 警告時表示著約束間存在沖突,而造成約束沖突的原因主要有:

  1. 約束太少
  2. 約束的優(yōu)先級沖突

針對調(diào)試解決辦法直接上圖(...懶了??)
resolvingAmbiguity5.png

總結(jié)

本視頻從約束布局的生命周期到如何Debug布局問題,對Autolayout引擎的工作流程做了充分了說明和Demo演示,也告訴了我們一些在使用Autolayout中值得注意的地方,對工作中使用和處理Autolayout問題有很大的幫助,作為唯一有字幕(當(dāng)然是英文的??)的介紹Autolayout的WWDC Session是值得一看.如果還有說明問題,歡迎留言,一起探討.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容