[譯] AsyncDisplayKit/Texture 官方文檔(1)

官方文檔連接:texturegroup.org/docs/gettin…css

開始使用 Texture

Texture 的基本單位是 NodeASDisplayNodeUIViewCALayer 的抽象,它與 UIKit 的不一樣在於:html

Node 能夠異步繪製,且線程安全,你能夠在在異步線程中進行實例化和配置它們的層級結構。前端

爲了保持用戶界面的流暢,你的 App 應該以 1/60 秒的幀率呈現, 這意味着主線程有 1/ 60 秒來處理一幀,也就是說,主線程須要在 16 毫秒內來執行全部的佈局和繪圖代碼,而因爲一些系統級別的開銷,你的佈局繪圖代碼通常執行超過 10 毫秒,就可能引發掉幀。node

Texture 可讓你將圖像解碼、文本渲染和其餘消耗性能的 UI 操做從主線程剝離,以保證主線程能夠流暢的響應用戶的交互,Texture 還有其餘的使用竅門,咱們稍後會講到。ios

節點/Node

若是你會使用 UIView,那麼你就已經知道如何使用 Node 了,UIView 中絕大部分的方法 Node 都有映射,而且 UIViewCALayer 大多數的屬性,也是可使用的。當屬性和方法的命名有差別時,例如 .clipsToBounds.masksToBoundsNode 默認使用 UIView 的命名,惟一例外的是 Node 使用 .position 替代了 .centercss3

固然,你也能夠經過 node.viewnode.layer 直接調用原生屬性和方法,但要確保它會在主線程上執行!git

Texture 已經提供了多種多樣的 Node 來替換你習慣使用的大部分 UIKit 組件,如今你已經能夠徹底經過 Texture 開發大規模的 App 。github

節點容器/Node Containers

當你將 Texture 集成到一個項目中時,一個常見的錯誤是將 Node 直接添加到已有的視圖中,這樣作的結果是你的節點在渲染時會閃爍。swift

正確的作法是,你應該把節點添加到 Node 容器中,由 Node 容器負責管理這些節點,你能夠把 Node 容器理解爲 UIKit 和 ASDK 之間的橋樑。xcode

佈局引擎/Layout Engine

Texture 的佈局很是強大,相對於傳統的 Frame,AutoLayout 等方式而言比較獨特,但對前端工做者並不陌生,Texture 的佈局基於 CSS FlexBox。它提供了指定自定義節點的大小和其子節點佈局的聲明方式,當全部的節點同時被渲染時,經過爲每一個節點提供的 ASLayoutSpec 異步計算 size 和佈局。

它和 UIStackView 很像,但支持低版本 iOS。

高級開發者功能

Texture 提供了在 UIKit 或 Foundation 中沒法找到的各類高級開發功能,咱們的開發人員發現,Texture 能夠簡化它們的架構,從而提升了開發效率。

完整列表即將推出...

沒放出來講個啥?

集成 Texture

若是你第一次使用 Texture,咱們建議你看看 ASDKgram 示例,咱們已經撰寫了一個 Guide(即將推出),指導你如何一步一步將 Texture 集成到一個 App 中。

沒放出來講個啥?

若是您遇到任何問題,請到咱們的 GitHub 或 Slack 尋求幫助。

資源

在 Slack 社區,和 Texture 的核心團隊及 700+ Texture 開發者一塊兒,實時 Debug、獲取更新和進行交流,點此註冊

示例

查看咱們的示例庫,若是你第一次使用 Texture,咱們建議你從 ASDKgram 開始,這個示例同時使用 UIKit 和 Texture 實現了照片Feed,你能夠對比查看它們的區別,它的特色是:

  1. 一個無限滾動的 Home Feed,演示 Texture 的平滑滾動性能;
  2. 一個至關龐大的代碼庫,用於演示使用 Texture 設計 App 能夠減小多少代碼;

視頻

教程/文章

FlexBox 佈局學習

Texture 強大的佈局系統基於CSS FlexBox 模型,這些網站對於學習 FlexBox 的基本知識很是有用。

安裝 Texture

Texture 可使用 CocoaPods 和 Carthage 安裝,使用時不要忘記導入頭文件:

#import <AsyncDisplayKit/AsyncDisplayKit.h>複製代碼

若是你使用 Swift 開發,可使用 Objective-C bridging header 進行橋接,若是你在安裝中遇到任何問題,請在 GitHub 或 Slack 聯繫咱們。

CocoaPods

使用 CocoaPods 安裝,將如下內容添加到 Podfile:

target 'MyApp' do
    pod "Texture"
end複製代碼

徹底退出 Xcode,打開終端,cd 到項目目錄,執行下面的命令:

pod install複製代碼

若是要更新 Texture,打開終端,cd 到項目目錄,執行下面的命令:

pod update Texture複製代碼

不要忘記使用 .xcworkspace 打開,而不是 .xcodeproj

Carthage(常規安裝)

使用迦太基須要建立一個Cartfile 列表,而後執行 carthage update,將依賴項下載到 Cathage/Checkouts 文件夾中,並將它們構建到位於 Carthage/Build 文件夾中,開發人員須手工集成到項目中。

Texture 也能夠經過迦太基安裝,將如下內容添加到 Cartfile 以獲取最新的 release 版本:

github "texturegroup/texture"複製代碼

或者獲取主幹:

github "texturegroup/texture" "master"複製代碼

Texture 有本身的 Cartfile,指明瞭本身的依賴項,Texture 所需的依賴會自動安裝,安裝 Texture 依賴須要使用終端,在Carthage/Checkouts 目錄下,執行:

carthage update複製代碼

確認 Texture、PINRemoteImage (3.0.0-beta.2)、PINCache 所有獲取和構建,Texture 的 Cartfile 會自動處理這些依賴關係。

打開 Xcode,將所需的框架拖到 TARGETS - General -Linked Frameworks and Libraries

Carthage(light)

Texture 不支持 Carthage 更輕量的使用方式,你須要手動添加項目文件, 這是由於 Texture 的依賴 PINCache 尚未項目文件,

PINCache 是 PINRemoteImage 一個嵌套的依賴。

若是沒有 PINRemoteImage 和 PINCache,你將沒法完整的使用 Texture 圖像功能集。

升級到 2.0

發佈說明

請閱讀 GitHub 上的官方發佈說明。

獲取正式候選版本

將如下內容添加到你的 pod 文件中:

pod 'Texture', '>= 2.0'複製代碼

在終端執行:

pod repo update
pod update Texture複製代碼

測試 2.0

一旦你更新到2.0,你會看到許多棄用警告。 別擔憂!這些警告是安全的,由於咱們已經橋接了全部舊的 API,以便在遷移到新的 API 以前對 2.0 進行測試。
若是你的 App 沒法構建成功而不是僅顯示警告,那麼你的項目中可能出現錯誤,你有幾個選擇:

  1. 在 project settings 中禁用 deprecation warnings;
  2. 在項目的 build settings 中禁用 warnings as errors;
  3. 在 Texture 中禁用 deprecation warnings,這須要你將 ASBaseDefines.h 中的第 74 行更改成 # define ASDISPLAYNODE_WARN_DEPRECATED 0

當你的 App 構建成功並運行,你須要測試它以確保一切正常工做。 若是你發現任何問題,請嘗試在該區域採用新的 API 並從新測試。

你可能會注意到一個關鍵的變化:

ASStackLayoutSpec的.alignItems 屬性默認值更改成 ASStackLayoutAlignItemsStretch 而不是 ASStackLayoutAlignItemsStart,這可能會在 UI 中形成失真。

若是還有其餘問題,請提交 GitHub issue,咱們很樂意幫助你!

聰明的預加載

異步併發渲染和 FlexBox 佈局已經很是強大,但 Texture 作到的不止於此,另一個重要的層面是智能預加載的思想。

正如在開始使用 Texture 這節中講的那樣,在一個節點容器的上下文以外使用一個節點有一些弊端的。這是由於全部的節點都具備當前界面狀態的概念,這個狀態命名爲 interfaceState

interfaceState 這個屬性是不斷更新的,它的更新由 ASRangeController 所控制,ASRangeController 又由全部的節點容器在內部建立和維護。

在容器外部使用的節點不會被 ASRangeController 更新狀態,所以這有時會致使閃爍,緣由是這些容器外的節點由於狀態的錯誤,在節點被渲染到屏幕後又進行了一次渲染。

Interface State Ranges

當將節點添加到滾動或分頁界面時,它們一般位於如下範圍中的一個。這意味着當滾動視圖被滾動時,它們的界面狀態將隨着它們的移動而更新。

一個節點的所處的範圍會是如下範圍中的一個:

界面範圍 描述
Preload 節點還不可見,這時節點收集外部源,外部源多是 API 或者本地磁盤。
Display 節點開始渲染,包括文本的光柵化已經圖像解碼等。
Visible 節點可見,在屏幕上至少擁有一個像素。

ASRangeTuningParameters

每一個範圍的大小以整個屏幕的尺寸做爲參照, 默認的 size 在許多用例中都能很好地工做,你也能夠經過在滾動節點上設置範圍參數來調整它們。

在上面的一個滾動集合的示例圖片中,用戶正在向下滾動。正如你所看到的,用戶滾動方向區域(領先方向)要比用戶離開方向區域(尾隨方向)大得多。爲了保持內存的最佳使用,當用戶改變滾動方向時,兩個區域會動態地交換。這使你沒必要考慮滾動方向的變化,只需關注領先方向和尾隨方向的區域大小。

在這張圖中,你能夠看到智能的預加載是如何進行工做的,你能夠看到在一個垂直的滾動容器中,雖然有些節點還未在設備屏幕中出現,可是它有一個範圍控制器,屏幕外的節點處在 Preload 數據準備範圍和 Display 渲染準備範圍。

Interface State Callbacks

當用戶滾動時,節點在這三個範圍中切換,並經過加載數據,渲染等做出適當的反應。你建立的節點子類能夠經過實現相應的回調方法進入此機制。

class TZYNode: ASDisplayNode {

    override func didEnterPreloadState() {
        print("進入數據加載範圍")
    }

    override func didExitPreloadState() {
        print("離開數據加載範圍")
    }

    override func didEnterDisplayState() {
        print("進入渲染範圍")
    }

    override func didExitDisplayState() {
        print("離開渲染範圍")
    }

    override func didEnterVisibleState() {
        print("進入可見範圍")
    }

    override func didExitVisibleState() {
        print("離開可見範圍")
    }

}複製代碼

節點容器/Node Containers

在節點容器中使用節點

咱們強烈建議你在節點容器中使用 Texture 的節點, Texture 提供如下節點容器:

節點容器 等價於 UIKit
ASCollectionNode 代替 UICollectionView
ASPagerNode 代替UIPageViewController
ASTableNode 代替UITableView
ASViewController 代替UIViewController
ASNavigationController 代替UINavigationController,實現 ASVisibility 協議。
ASTabBarController 代替UITabBarController,實現 ASVisibility 協議。

示例代碼和特定示例項目會在每一個節點容器的文檔中突出顯示。

爲何使用節點容器

節點容器自動管理其子節點實現智能預加載,這意味着節點的全部佈局計算,數據讀取,解碼和渲染都將會異步完成,這就是爲何咱們建議將節點放進節點容器中使用的緣由。
請注意,儘管你能夠直接使用節點而不加入節點容器,但除非你添加其餘回調,不然這個容器外的節點只會在屏幕出現時纔會開始渲染。如同 UIKit 所作的那樣,這可能致使性能降低和內容閃爍。

節點子類/Node Subclasses

在 UIKit 組件上使用節點的一個主要優勢是,全部的節點都預先在主線程佈局並繪製,這樣主線程就能夠當即響應用戶交互事件,而無需先處理控件的渲染,Texture 提供如下節點:

節點 等價於 UIKit
ASDisplayNode 代替 UIView,全部的 Node 都繼承自 ASDisplayNode。
ASCellNode 代替 UITableViewCell&UICollectionViewCell,須要和 ASTableNode,ASCollectionNode 和 ASPagerNode 共同使用。
ASScrollNode 代替 UIScrollView,這個節點對於建立自定義的,包含其餘節點的可滾動區域很是有用。
ASEditableTextNode 代替 UITextView。
ASTextNode 代替 UILabel。
ASImageNode 代替 UIImage。
ASNetworkImageNode 代替 UIImage。
ASMultiplexImageNode 代替 UIImage。
ASVideoNode 代替 AVPlayerLayer。
ASVideoPlayerNode 代替 UIMoviePlayer。
ASControlNode 代替 UIControl。
ASButtonNode 代替 UIButton。
ASMapNode 代替 MKMapView。

儘管與 UIKit 組件大體至關,但通常而言,Texture 節點提供了更高級的功能和便利。 例如,ASNetworkImageNode 能夠自動加載網絡圖片和進行緩存管理,甚至支持漸進式 JPEG 和動畫 GIF。

AsyncDisplayKitOverview 示例應用程序給出了上面列出的每一個節點的基本實現。

節點繼承關係/Node Inheritance Hierarchy

全部的 Texture 節點都繼承自 ASDisplayNode

Node層級
Node層級

原圖使用花體英文,查看原圖

右側的節點是 UIKit 元素的封裝。 例如,ASScrollNode 封裝了一個 UIScrollView,而 ASCollectionNode 封裝了一個 UICollectionViewliveMapMode 中的 ASMapNodeUIMapView 的封裝。

liveMapMode 未在此節和以前章節出現,不清楚是否爲筆誤。

節點實例/Subclassing

建立子類時最重要的區別是你使用的是 ASViewController 仍是 ASDisplayNode,這聽起來很明顯,可是由於這其中有一些微妙的差別,因此記住這點仍是至關重要的。

ASDisplayNode

雖然實例化節點與 UIView 相似,但須要遵循一些原則,以確保你充分利用了它的能力,並確保節點按照預期的方式運行。

-init

在使用 initNodeBlocks 時,這個方法會後臺線程上被調用。可是,由於沒有其餘方法會在 init 完成以前運行,因此這個方法不須要加鎖。

須要記住的最重要的一點是,init 方法必須可以在任何隊列上調用。最值得注意的是,你永遠不該該在節點初始化方法中初始化任何 UIKit 對象,以及調用 node.layer node.view.x 等與viewlayer 有關的操做,也不該該在這個方法中爲節點添加手勢,這些事件應該在 didLoad 方法中進行。

-didLoad

這個方法在概念上相似於 UIViewController-viewDidLoad 方法,當後臺視圖初始化完成時,它會被調用一次,它保證會在主線程上被調用,是執行任何 UIKit 代碼合適的地方,例如添加手勢識,更改 viewlayer,初始化 UIKit 對象。

-layoutSpecThatFits:

該方法定義了節點的佈局,並在後臺線程上進行了大量的計算。此方法是你聲明、建立和修改 ASLayoutSpec 佈局描述對象的地方,該對象描述了節點的 size,以及其子節點的 size 和 position,是你放置大部分佈局代碼的地方。

ASLayoutSpec 對象直到在此方法中返回前是可變的。 在這以後,這個對象將不可改變,須要注意的是你不須要緩存 ASLayoutSpec 對象以備後用,咱們建議你在必要時從新建立佈局描述。

因爲它在後臺線程上運行,所以你不能在這個方法中調用 node.viewnode.layer 以及它們的屬性。 此外,除非你明確知道本身在作什麼,不然不要在此方法中建立其餘節點。 另外,重寫此方法並不必定須要調用 super 方法。

-layout

在此方法中調用 super 將,會使用 layoutSpec 對象計算佈局,全部子節點都將計算其 size 和 position。

-layout 在概念上相似於 UIViewController-viewwilllayoutsubview,這是一個更改 hidden 屬性、修改 view 屬性、設置背景顏色的好地方。你能夠在 -layoutspec: 方法中設定背景顏色,但這可能會存在時序問題。若是你須要使用原生的 UIView,能夠在這裏設置它們的 frame,無論怎樣,你始終可使用 -initWithViewBlock: 建立節點,並在其餘地方的後臺線程中進行調整。

這個方法在主線程上被調用,若是你使用的是 ASLayoutSpec,那麼你不該該過多地依賴這個方法,由於在主線程上進行佈局是很是可取的,須要這個方法的子類小於 1/10。

使用 -layout 的一個重要用途是你須要子節點的 size 是精確的。舉例來講,當你但願一個 collectionNode 能夠鋪面屏幕,這種狀況不被 ASLayoutSpec 很好的支持,此時最簡單的作法是在這個方法中手動設定 frame

subnode.frame = self.bounds複製代碼

若是你但願在 ASViewController 中獲得相同的效果,那麼你能夠在 -viewWillLayoutSubviews 中作一樣的事情,不過若是你的節點經過 initWithNode: 進行實例化,它會自動作到這一點。

ASViewController

ASViewController 是一個常規的 UIViewController 子類,它具備管理節點的特殊功能。由於它是一個 UIViewController 子類,因此全部的方法都在主線程上被調用,而且你應該在主線程上建立至少一個 ASViewController

-init

這個方法在 ASViewController 的生命週期開始時被調用一次,與 UIViewController 的初始化同樣,你最好不要在這個方法中訪問 self.viewself.node.view,由於這樣會強制建立 view。 這些操做能夠在 -viewDidLoad 中進行,-viewDidLoad 能夠執行任何 view 的訪問。

ASViewController 指定的構造器是 initWithNode:,一個典型的構造器看起來就像下面的代碼。請注意下面的代碼,在調用 super 以前,ASViewController 的節點是如何被建立的,ASViewController 管理節點相似於 UIViewController 管理視圖,可是它的初始化方式有所區別:

class TZYVC: ASViewController<ASDisplayNode> {

    init() {
        let pagerNode = ASPagerNode()
        super.init(node: pagerNode)
        pagerNode.setDataSource(self)
        pagerNode.setDelegate(self)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}

extension TZYVC: ASPagerDataSource {

    func numberOfPages(in pagerNode: ASPagerNode) -> Int {
        return 10
    }

}

extension TZYVC: ASPagerDelegate {


}複製代碼

-loadView

咱們建議你不要使用這個方法,由於與 -viewDidLoad 相比,它沒有什麼特別的優點,而且有一些缺點。 可是,只要不將 self.view 屬性設置爲不一樣的值,它能夠安全的使用。 它的 super 方法會將其封裝的 UIViewControllerview 設置爲 ASViewControllernode.view

-viewDidLoad

這個方法在 -loadView 以後被執行,這是 ASViewController 生命週期中,你能夠訪問 node.view 最先的方法,你能夠在這份方法中任意修改 viewlayer 或添加手勢,這個方法在其所屬的生命週期中,只會執行一次。

因此佈局代碼不該該放在這個方法中,由於當界面重繪時,這裏的代碼不會被再次調用。UIViewController 中這個方法也是一樣的,在這種方法中放置佈局代碼是一種不太好的作法,即便你的佈局不會由於交互發生變化。

-viewWillLayoutSubviews

這個方法會與節點的 -layout 同時調用,它可能在 ASViewController 的生命週期中被屢次調用,當 ASViewController 的節點的邊界發生改變,如旋轉、分割屏幕、鍵盤彈出等行爲,或者當視圖的層次結構發生變化,如子節點添加、刪除或改變大小時,這個方法將被調用。

由於它不常常被調用,可是調用就表明頁面須要重繪,所以全部的佈局代碼最好都放在這個方法中,即便是不直接依賴於 size 的 UI 代碼也應放在這裏。

-viewWillAppear: / -viewDidDisappear:

viewWillAppearASViewController 的節點出如今屏幕上以前被調用,這是節點從屏幕出現的最先時間,viewDidDisappear 在控制器從視圖層次結構中移除以後被調用,這是節點從屏幕消失的最先時機,這兩個方法提供了一個很好的時機來啓動或中止與控制器相關的動畫,這也是一個保存和記錄用戶行爲日誌的好地方。

儘管這些方法可能被屢次調用,而且是能夠執行佈局代碼的,可是這兩個方法不會在全部須要重繪的時候被調用,所以除了特定的動畫設置以外,不該該用於執行核心的佈局代碼。

未完待續

[譯] AsyncDisplayKit/Texture 官方文檔(2)

相關文章
相關標籤/搜索