本文為WWDC2015的Session 219 "Mysteries of Auto Layout Part2" 視頻筆記,其內(nèi)容主要涉及了約束的生命周期和,Autolayout調(diào)試兩大內(nèi)容,學習記錄了視頻內(nèi)容重要的知識內(nèi)容,歡迎一起探討研究.
資源
內(nèi)容
The Layout Cycle
為了說明
Layout Cycle
,蘋果工程師給出了這樣以上這張圖,果然一圖勝千言.基于整個App的運行循環(huán)過程中,布局界面上的視圖前,首先會進行約束進行更新和設置,然后將最終的布局信息延時地傳遞給視圖,讓視圖獲取到相關Frame的信息,進行位置的尺寸的確定,然后回到主運行循環(huán),等待約束再發(fā)生變化.
Constraints Change
- 約束改變后
Frame
不會馬上變化 - 重寫
layoutSubviews
要十分當心
讓約束發(fā)生變化的方式主要由以下三種:
1.使用官方極力推薦的NSLayoutConstraint
的``active和
deactive`兩個類方法來激活,或無效指定約束.(拋棄掉add/remove約束的方式吧~原因可見Mysteries of Auto Layout Part1 16:27)
方法代碼如下:
[NSLayoutConstraint activateConstraints:]
[NSLayoutConstraint deactivateConstraints:]
// 參數(shù)為NSLayoutConstraint對象的數(shù)組
2.修改約束等式的常量值,乘數(shù)因子或者優(yōu)先值.接觸過Autolayout我們應該都知道給視圖設置約束時要滿足一個約束等式如下.(就當你知道了,(╯﹏╰)b)
當
Constant
或者Multipler
變化時,創(chuàng)建的約束等式也相應改變,使得Layout
引擎重寫計算布局.而對于優(yōu)先值
Priority
的改變,往往表現(xiàn)在兩個視圖間同一位置的約束,將根據(jù)優(yōu)先級高的計算布局屬性,除此之外還有具有instrinsic Content Size
屬性的視圖間的contentCompressionResistance
或者contentHug
的競爭.
3.添加或移除視圖,視圖都沒,跟自己相關的約束當然也沒有嘍.(╮(╯▽╰)╭)
當約束改變后,Layout
引擎就會重新計算新的布局,將布局內(nèi)容的舊值替換成新值,然后調(diào)用父視圖的setNeedsLayout
.
而對于setNeedsLayout
的描述,官方文檔給出了詳細說明.此方法只是對當前約束變化了的視圖了標記,只有等到下一個視圖更新周期時視圖才會真正響應約束的變化而改變Frame
.如果想要讓視圖快速地響應約束的變化,則需要調(diào)用layoutIfNeeded
.
Deferred Layout Pass
約束發(fā)生變化后,就進入了延遲的布局信息傳遞過程.為什么說延時的呢?回想一下,我們操作約束變化時經(jīng)常通過設置動畫時間來放大對應Frame的延時改變.在這個階段里,視圖更新所在視圖層次內(nèi)的所有約束,然后重新賦值Frame
屬性.
更新視圖的約束,使用setNeedsUpdateConstraints
就表示著該視圖的約束需要更新,而具體的更新會在將來某一時刻進行.其調(diào)用的時機,蘋果工程師給了兩個情景:
- 當某約束在所在位置變化太慢時,使用
update
期間將更快的更新約束. - 當視圖約束頻繁且多余的變化時,調(diào)用后只會執(zhí)行最后一次的更新變化.
響應視圖布局約束變化后,就到了對視圖位置布局的最終設置,而這個過程則是視圖從上到下遍歷視圖層次,調(diào)用layoutSuviews(iOS)/layout(OSX)
,設置具體的內(nèi)部子視圖的Frame
.而重寫該方法時,主講人多次提醒開發(fā)者需要十分注意重寫方法時內(nèi)部的操作.
重寫layoutSuviews
方法時,其內(nèi)部的約束是不完整的,具體表現(xiàn)為有的子視圖已經(jīng)完成了布局,而有的子視圖正在或者還未進行布局.為了保證方法的正確執(zhí)行,我們必須調(diào)用父類的layoutSuviews
,不能在其內(nèi)部調(diào)用setNeedsUpdateConstraints
(時機太晚了,已經(jīng)進入了布局階段),并且不能隨意地更改約束,防止與其他視圖層次相關的約束的改變.
Interacting Legacy Layout (處理系統(tǒng)遺留的布局)
-
當我們用代碼使用Autolayout給視圖添加約束時,要時刻留意將
translatesAutoresizingMaskIntoConstraints`設為NO,否則添加完約束后就會出現(xiàn)一下約束警告日志. - 如果想要自己設置內(nèi)部視圖的
Frame
時,重寫layoutSuviews
,在此方法里設置,切記不要忘記調(diào)用父類方法.
Constraint Creation
關于系統(tǒng)自帶API進行約束的創(chuàng)建方式一直以來都被我們詬病,設個約束出要那么大坨代碼(差評~)...但如果了解使用VFL創(chuàng)建約束的話還是很優(yōu)雅的,只是實現(xiàn)的約束有所限制.而現(xiàn)在iOS9提供了新的約束創(chuàng)建方式,讓開發(fā)者可以更加明了,快速地創(chuàng)建約束.
通過查看
UIView
的頭文件,可以看到view
的anchor
屬性都定義在一個名為UIViewLayoutConstraintCreation
的UIView
分類中.
// NSLayoutXAxisAnchor 類型表示在X軸上的約束
leadingAnchor
trailingAnchor
leftAnchor
rightAnchor
centerXAnchor
// NSLayoutXAxisAnchor 類型表示在Y軸上的約束
topAnchor
bottomAnchor
centerYAnchor
firstBaselineAnchor
lastBaselineAnchor
// NSLayoutDimension 類型表示尺寸相關的約束
widthAnchor
heightAnchor
初次之外,新的NSLayoutAnchor
類的文件里提供了一系列進行相關視圖進行約束設置的方法,這里就不一一介紹,可以Command + R
進行看看.
Constraining Negative Space
這里所提到的關于對多個視圖進行等間距或者同時居中的情況下,以前的做法就是創(chuàng)建假的UIView
僅僅為提供約束來達成目的,而現(xiàn)在有了UILayoutGuide
對象其表示著一個可以使用Autolayout的布局矩形區(qū)域,可以通過視圖的分類方法addLayoutGuide
添加guide
,來充當之前僅僅提供約束的假視圖,作用于Autolayout
.具體的話就舉一個實現(xiàn)讓三個按鈕等間距排列,結(jié)合代碼和圖應該能剛好理解點.
//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
的具體的相關約束以及關聯(lián)對象,就必須要理解輸出的約束警告日志.
現(xiàn)在允許給約束或者視圖添加約束標識符
identifier
字符串屬性,將會在日志輸出中顯示,極大讓日志內(nèi)容更加清晰,讓開發(fā)者快速找到存在問題的約束和視圖.
Resolving Ambiguity
出現(xiàn)Ambigous Layout 警告時表示著約束間存在沖突,而造成約束沖突的原因主要有:
- 約束太少
- 約束的優(yōu)先級沖突
總結(jié)
本視頻從約束布局的生命周期到如何Debug布局問題,對Autolayout引擎的工作流程
做了充分了說明和Demo演示,也告訴了我們一些在使用Autolayout中值得注意的地方,對工作中使用和處理Autolayout問題有很大的幫助,作為唯一有字幕(當然是英文的??)的介紹Autolayout的WWDC Session是值得一看.如果還有說明問題,歡迎留言,一起探討.