在上一篇介紹中咱們曾經討論過Autolayout的性能問題。然而在iOS中,除了Autolayout,能選擇的只有autoresizingMask,或者純手動佈局。在寫了無數view.frame = CGRect(…)以後,咱們才發現,一個在HTML中很是簡單的流式佈局,到iOS9纔有相應的UIStackView予以支持。儘管你可使用 FDStackView 將系統要求下降到iOS6,對於複雜的佈局仍然須要多層View嵌套來實現——其實對於實現stack佈局的時候,並不須要一個UIView實例來承載全部的元素,只須要它的佈局功能而已。javascript
作過Web開發的朋友已經習慣了高效的css佈局:聲明式、易於調試,boxModel結構化清晰等等優勢,特別是使用自動化工具以後,只須要保存文件就能夠當即在瀏覽器中看到更新後的效果;而這一切在iOS中就變得高不可攀:命令式賦值、編譯後(Objc速度尚可,而swift編譯速度較慢)才能看到結果、Autolayout閉源、視圖調試複雜、xcode常常crash等等。若是要實現一個高性能的tableView,手寫佈局幾乎是惟一選擇。css
在決定使用哪一種佈局方式以前,先看看設計師是怎麼思考佈局的:前端
設計師最終肯定的,是一個佈局規則。java
設計稿到了工程師這邊之後,絕大多數時間都在作如下兩件事:node
這樣層層遞歸,最終完成整個屏幕內全部子元素的佈局。工程師完成的,是一個基於佈局規則的具體實現。ios
也就是說,手動佈局或者經過約束(Autolayout)實際上是在『實現』佈局規則,而不是『聲明』佈局規則。抽象層級降低了,隨之而來的是多到使人頭疼的frame、size、origin計算,可讀性、可維護性都很是差。那能不能用一個數據結構來表示佈局規則,提升抽象層級,從而擺脫繁重又容易出錯的數值計算,讓佈局系統根據規則自動地、異步地計算呢?git
這是最基礎的一種佈局方式。在ASDK中的手動佈局與UIKit相似,只是方法名從sizeThatFits變成了calculatedSizeThatFits,layoutSubviews方法變成了layout方法。略微不一樣的是ASDK會將佈局結果異步預先計算,並緩存下來以提高性能,這點對於tableView滾動性能來講有很是大的幫助。github
然而,跟普通手動佈局相似,最大的缺點是可讀性和可維護性差。因爲自身的大小經常和子元素的佈局相關聯,這兩個方法中的代碼容易重複;同時因爲佈局針對自身subView,很難將其代碼與其餘View進行復用。swift
這也是在ASDK中新出現的概念。先介紹一下ASLayout:xcode
一個ASLayout對象包含如下元素:
能夠看出,當一個node具有了肯定的ASLayout對象時,它自身的佈局也就隨之肯定了。爲了生成ASLayout,ASDisplayNode爲subclass提供了以下覆蓋點:
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize複製代碼
只要Node可以計算出本身的ASLayout,父元素就能夠完成對其的佈局。這種方法將sizeThatFits和layoutSubviews結合在一塊兒,必定程度上避免了類似代碼的尷尬,可是計算上仍然是手動佈局,不夠簡便。
有了ASLayout這一層抽象,再來看如何聲明規則來生成它。這也是最艱鉅的部分。
Facebook將React的概念延伸到native,同時也把聲明式的語法帶到了iOS,產生了ComponentKit框架。早在ASDK1.0的年代你們紛紛表示但願能將其與ComponentKit相融合,幸運的是,在2.0版本中實現了。我選用了做者Scott
Goodson在NSSpain的演講pdf做爲插圖,方便你們瞭解新的佈局系統。
所以Automatic Layout是ASDK最推薦也是最爲高效的佈局方式。它引入了ASLayoutSpec的概念,能夠理解爲一個抽象的容器(並不須要建立對應node或者view來裝載子元素),只須要爲它制定一系列的佈局規則,它就能對其負責的子元素進行佈局。
咱們先來看一下它們之間的關係:
能夠看到ASLayoutSpec和ASDisplayNode都實現了ASLayoutable接口,所以他們都具有生成ASLayout的能力,這樣就能惟一肯定自身的大小。
因爲ASLayoutSpec只負責指定佈局規則,而不關心其佈局的ASLayoutable具體是Node仍是其餘ASLayoutSpec,咱們能夠輕鬆地將ASLayoutSpec生成邏輯獨立出來,達到複用的目的。
ASLayoutSpec主要有如下幾種:
經過它們的命名就能夠了解其大體做用。其中用途最普遍的無疑是ASStackLayoutSpec,與UIStackView有殊途同歸之妙。
ASStackLayoutSpec大量借鑑了CSS的FlexBox概念,寫過Web代碼的同窗應該能一眼認出許多熟悉的屬性:justifyContent/flexDirection/alignSelf/alignItems/flexBasis等等。不熟悉的朋友也能夠經過一個有趣的遊戲來學習flexbox:flexboxfroggy.com/
(圖中的Huy Nguyen也是ASDK佈局的主要貢獻者之一)
圖中左邊是一個imageNode,右邊是由兩個textNode組成的一個vertical
stack,再和imageNode組合成一個橫向的stack,最後加上邊緣inset完成整個佈局。
事實上,與css相似,絕大多數的佈局均可以經過stack和inset的組合來完成;而和UIStackView不一樣的是,layout spec只是一個存在於內存之中的數據結構,並不須要額外建立view容器來承載子元素,大大節約了複雜佈局帶來的開銷;同時由於它的輕量級和獨立性,所以可以將佈局規則放到後臺線程獨立計算,並緩存在node之中,對於大量tableView/collectionView的CellNode快速佈局有至關大的幫助。
Huy Nguyen也爲ASLayoutSpec寫了一個寓教於樂的小遊戲,只是將上面提到的的針對css的小遊戲版本改爲了Objc,方便你們快速學習。
在最近的版本中,ASDK也同時支持 Yoga (一個跨平臺的flexbox引擎,使用C語言實現)來計算基於flexbox的佈局,與ASDK自己實現的flexbox概念相似。
即刻在多個消息頁面使用了ASDK新的佈局系統,例如:
從咱們的實踐經驗來看有如下優缺點:
雖然咱們沒有在整個項目都採用新的的佈局方式,然而ASDK帶來的啓發是深遠的:聲明式、異步佈局、flexBox、緩存等等。咱們也看到有一些其餘佈局庫在聲明式佈局作許多的嘗試,如Brickkit, Layoutkit等等,或許這就會是未來佈局系統發展的趨勢,大大加快咱們平時的開發和維護效率。