Texture原名是AsyncDisplayKit,是Facebook的paper團隊釋出的一個基于UIKit的庫,這個庫能夠将圖檔加載、布局計算以及UI渲染等操作均放在背景線程,進而可以極大地優化APP界面的流暢度。
在之前的文章iOS的性能優化中我詳細介紹了卡頓産生的原因,這裡不做贅述,總結成一句話就是:GPU或者CPU的消耗過大,導緻在一次同步信号之間沒有準備完成,沒有内容送出,導緻掉幀。而Texture的最大特點就是能夠極大地優化卡頓問題,其優化原理如下:
- 布局:iOS的Autolayout在性能上是存在瓶頸的,并且隻能在主線程進行計算,是以Texture棄用了AutoLayout,自己設計了一套布局方式。
- 渲染:對于大量文本、圖檔等的渲染,UIKit元件隻能在主線程進行,可能會造成GPU繪制的資源緊張;而ASDK會在背景異步繪制圖層,不會阻塞主線程的運作。
實際上,ASDK的最大特點就是異步。将消耗時間的渲染、圖檔解碼、布局計算、以及其他UI操作等等全部移除主線程,這樣主線程就可以對使用者的操作及時作出響應,進而達到流暢運作的目的。
控件

上圖是常見的UIView和CALayer的關系:View持有Layer用于展示,View本身會響應觸摸事件。
上面兩圖展示了ASNode、UIView以及CALayer三者的關系。
Texture幾乎封裝了UIKit中的所有常用控件,二者的對應關系如下:
Nodes
Node Containers
子父類關系
ASDisplayNode
其作用等同于UIView,是所有Node的父類。需要注意的是,ASDisplayNode也擁有一個view屬性,是以ASDisplayNode及其子類都可以通過這個view來添加UIKit控件,是以Texture可以和UIKit混用。
- (void)viewDidLoad {
//在UIKit中添加ASDisplayNode
ASDisplayNode *displayNode = [[ASDisplayNode alloc] init];
displayNode.frame = CGRectMake(10, 100, 200, 300);
displayNode.backgroundColor = UIColor.redColor;
[self.view addSubnode:displayNode];
//在ASDisplayNode中添加UIKit的方式1
UIView *subView1 = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 60, 60)];
subView1.backgroundColor = UIColor.orangeColor;
[displayNode.view addSubview:subView1];
//在ASDisplayNode中添加UIKit的方式2
ASDisplayNode *subNode2 = [[ASDisplayNode alloc] initWithViewBlock:^UIView * _Nonnull{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(10, 100, 60, 60)];
view.backgroundColor = UIColor.yellowColor;
return view;
}];
[displayNode addSubnode:subNode2];
}
複制
在ASDisplayNode中添加UIKit的方式2最終生成的是block傳回的UIKit對象,但是外部表現的是ASDisplayNode。
ASCellNode
作用等同于UITableViewCell或者UICollectionViewCell,自帶indexPath屬性,有些時候很有用。
ASTextNode
作用等同于UILabel,與UILabel不同的是,ASTextNode必須通過attributedString來設定文字。
ASTextNode2
在ASTextNode的基礎上修複了一些Bug。
ASImageNode
作用等同于UIImageView,但是隻能設定靜态圖檔,如果需要設定網絡圖檔,那麼需要使用ASNetworkImageNode。
ASNetworkImageNode
作用等同于UIImageView,當需要加載網絡圖檔的時候會使用此類,Texture用的是第三方的圖檔加載庫PINRemoteImage。ASNetworkImageNode并不支援gif,如果需要顯示gif的話推薦使用FLAnimatedImage。
ASButtonNode
作用等同于UIButton,但是需要特别注意imageAlignment和contentSpacing這兩個屬性,如下:
ASButtonNode *buttonNode = [[ASButtonNode alloc] init];
buttonNode.frame = CGRectMake(10, 200, 100, 60);
[buttonNode setTitle:@"按鈕" withFont:[UIFont systemFontOfSize:16] withColor:UIColor.blackColor forState:UIControlStateNormal];
[buttonNode setImage:[UIImage imageNamed:@"btnimgname"] forState:UIControlStateNormal];
/*調整圖檔和文字的排列方式,有兩個選擇:
*ASButtonNodeImageAlignmentBeginning,圖檔在前,文字在後
*ASButtonNodeImageAlignmentEnd,文字在前,圖檔在後
*/
buttonNode.imageAlignment = ASButtonNodeImageAlignmentEnd;
//*調整圖檔和文字的間距
buttonNode.contentSpacing = 10;
[displayNode addSubnode:buttonNode];
複制
ASTableNode
作用等同于UITableView,但是并未采用UITableView的重用機制。
并且,ASTableNode并沒有像UITableView一樣提供一個
- tableView: heightForRowAtIndexPath:
協定方法來決定每個cell的高度,而是由ASCellNode本身決定,這樣的一個好處就是,可以很輕易地實作動态的高度。
布局
AsyncDicplayKit擁有自己的一套成熟的布局方案,雖然文法比Masonry等(對AutoLayout的封裝)要複雜,但是其性能卻比AutoLayout好得不是一點點。
一、QuickStart(快速學習)
先來說一些基本概念。
1、LayoutSpecs(布局規則)
“LayoutSpecs”是“Layout Specifications”的縮寫,沒有實體存在。
LayoutSpecs是充當其他LayoutElements的容器,來解釋這些子LayoutElements是如何互相關聯的。
AsyncDisplayKit提供了ASLayout的幾個子類,後面會有介紹。
從插入單個簡單布局到更多更複雜的布局規則,變化堆放排列配置。
2、LatoutElements(布局元素)
LayoutSpecs包含并排列LayoutElements。
所有的ASDisplayNodes和ASLayoutSpecs都符合<ASLayoutElements>協定,這意味着你可以從LayoutNode和其他LayoutSpecs構成LayoutSpecs。
3、組合LayoutSpecs和LayoutElements,建立複雜UI
通過下圖我們可以看到如何将ASTextNode(黃色高亮)、ASVedioNode(頂部圖像)和ASStackLayoutSpec(堆棧布局規則)組合來建立複雜布局。
使用ASCenterLayoutSpec(中心布局規則)和ASOverlayLayoutSpec(覆寫布局規則)來放置頂部ASVedioNode(頂部圖像)。
4、一些Node需要設定初始大小
有一些元素,基于其可用内容,是有一個“固定大小”的,此時我們無需給其設定初始大小。
例如,ASTextNode就可以根據其屬性字元串計算其大小,其他具有固定大小的Node包括:
- ASTextNode
- ASTextNode2
- ASImageNode
- ASButtonNode
有一些Node在其外部資源加載完成之前,沒有或者缺乏“固定大小”。
例如,在從URL下載下傳圖檔之前,ASNetworkImageNode就不知道它的大小。這些種類還包括:
- ASVedioNode
- ASVedioPlayerNode
- ASNetworkImageNode
- ASEditableTextNode
缺乏初始固有大小的這些Node,必須設定它們的初始大小,使用ASRatioLayoutSpec(比例布局規則)、ASAbsoluteLayoutSpec(絕對布局規則)或者對象的size屬性。
二、Layout Examples(布局示例)
1,簡單标題左右對齊
這種布局通過3個布局規則來實作:
一個垂直的ASStackLayoutSpec、一個水準的ASStackLayoutSpec和ASInsetLayoutSpec(用于插入整個标題)。
布局的組成(layout specs + Nodes)如下圖所示:
代碼如下:
2、圖檔上覆寫文本
這種是通過兩個布局規則來實作的:
一個是用于插入文本的ASInsetLayoutSpec,還有一個是将插入文本覆寫在圖檔上的ASOverlayLayoutSpec。
代碼如下:
3、圖檔上覆寫一個圖示
可以通過絕對布局來實作,代碼如下:
三、Layout Specs(布局規則)
以下ASLayoutSpec的子類,用于組成簡單或複雜的布局:
- ASInsetLayoutSpec,插入布局
- ASOverlayLayoutSpec,覆寫布局
- ASBackgroundLayoutSpec,背景布局
- ASCenterLayoutSpec,中心布局
- ASRatioLayoutSpec,比例布局
- ASStackLayoutSpec,堆疊布局(Flexbox布局思想)
- ASAbsoluteLayoutSpec,絕對布局
你也可以子類化ASLayoutSpec,用以自定義一個ASLayoutSpec。
四、ASStackLayoutSpec(堆疊布局規則)
在AsyncDisplayKit的所有LayoutSpecs中,ASStackLayoutSpec是最強大的,ASStackLayoutSpec使用flexbox算法來确定其子節點的位置和大小,Flexbox旨在不同的螢幕尺寸上提供一緻統一的布局。在堆疊布局中,以垂直或水準堆疊對齊item,堆疊布局可以是另一堆疊布局的子布局,這使得可以使用ASStackLayoutSpec來建立任何布局。
ASStackLayoutSpec的屬性介紹如下:
- direction,主軸的方向,指定子項的堆疊方向,預設是縱向。
- spacing,每個子元素之間的距離,即主軸上視圖排列的間距。
- horizontalAlignment,水準對齊方式
- verticalAlignment,垂直對齊方式
- justifyContent,主軸上的排列方式,分五種:從前往後排列、居中排列、從後往前排列、間隔排列(兩端無間隔)、間隔排列(兩端有間隔)。
- alignItems,交叉軸上的排列方式
- flexWrap
- alignContent
- lineSpacing
Flexbox在ASDK中的工作方式與CSS在Web中的工作方式是相同的。
五、ASStackLayout布局元素屬性
僅針對ASStackLayoutSpec布局的元素有效。
六、ASLayout布局元素屬性
後記:本文隻是對ASDK做了一個簡單的介紹,通過本文可以對Texture有個初步了解,但是要想真正上手去做項目,還是要下一番功夫的,建議參考這篇文章:https://github.com/Luis-X/Facebook-Texture
以上。