天天看點

Texture

Texture原名是AsyncDisplayKit,是Facebook的paper團隊釋出的一個基于UIKit的庫,這個庫能夠将圖檔加載、布局計算以及UI渲染等操作均放在背景線程,進而可以極大地優化APP界面的流暢度。

在之前的文章iOS的性能優化中我詳細介紹了卡頓産生的原因,這裡不做贅述,總結成一句話就是:GPU或者CPU的消耗過大,導緻在一次同步信号之間沒有準備完成,沒有内容送出,導緻掉幀。而Texture的最大特點就是能夠極大地優化卡頓問題,其優化原理如下:

  1. 布局:iOS的Autolayout在性能上是存在瓶頸的,并且隻能在主線程進行計算,是以Texture棄用了AutoLayout,自己設計了一套布局方式。
  2. 渲染:對于大量文本、圖檔等的渲染,UIKit元件隻能在主線程進行,可能會造成GPU繪制的資源緊張;而ASDK會在背景異步繪制圖層,不會阻塞主線程的運作。

實際上,ASDK的最大特點就是異步。将消耗時間的渲染、圖檔解碼、布局計算、以及其他UI操作等等全部移除主線程,這樣主線程就可以對使用者的操作及時作出響應,進而達到流暢運作的目的。

控件

Texture

上圖是常見的UIView和CALayer的關系:View持有Layer用于展示,View本身會響應觸摸事件。

Texture
Texture

上面兩圖展示了ASNode、UIView以及CALayer三者的關系。

Texture幾乎封裝了UIKit中的所有常用控件,二者的對應關系如下:

Nodes

Texture

Node Containers

Texture

子父類關系

Texture

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(堆棧布局規則)組合來建立複雜布局。

Texture

使用ASCenterLayoutSpec(中心布局規則)和ASOverlayLayoutSpec(覆寫布局規則)來放置頂部ASVedioNode(頂部圖像)。

Texture

4、一些Node需要設定初始大小

有一些元素,基于其可用内容,是有一個“固定大小”的,此時我們無需給其設定初始大小。

例如,ASTextNode就可以根據其屬性字元串計算其大小,其他具有固定大小的Node包括:

  • ASTextNode
  • ASTextNode2
  • ASImageNode
  • ASButtonNode

有一些Node在其外部資源加載完成之前,沒有或者缺乏“固定大小”。

例如,在從URL下載下傳圖檔之前,ASNetworkImageNode就不知道它的大小。這些種類還包括:

  • ASVedioNode
  • ASVedioPlayerNode
  • ASNetworkImageNode
  • ASEditableTextNode

缺乏初始固有大小的這些Node,必須設定它們的初始大小,使用ASRatioLayoutSpec(比例布局規則)、ASAbsoluteLayoutSpec(絕對布局規則)或者對象的size屬性。

二、Layout Examples(布局示例)

1,簡單标題左右對齊

Texture

這種布局通過3個布局規則來實作:

一個垂直的ASStackLayoutSpec、一個水準的ASStackLayoutSpec和ASInsetLayoutSpec(用于插入整個标題)。

布局的組成(layout specs + Nodes)如下圖所示:

Texture

代碼如下:

Texture
Texture

2、圖檔上覆寫文本

Texture

這種是通過兩個布局規則來實作的:

一個是用于插入文本的ASInsetLayoutSpec,還有一個是将插入文本覆寫在圖檔上的ASOverlayLayoutSpec。

代碼如下:

Texture

3、圖檔上覆寫一個圖示

Texture

可以通過絕對布局來實作,代碼如下:

Texture

三、Layout Specs(布局規則)

以下ASLayoutSpec的子類,用于組成簡單或複雜的布局:

  1. ASInsetLayoutSpec,插入布局
  2. ASOverlayLayoutSpec,覆寫布局
  3. ASBackgroundLayoutSpec,背景布局
  4. ASCenterLayoutSpec,中心布局
  5. ASRatioLayoutSpec,比例布局
  6. ASStackLayoutSpec,堆疊布局(Flexbox布局思想)
  7. ASAbsoluteLayoutSpec,絕對布局

你也可以子類化ASLayoutSpec,用以自定義一個ASLayoutSpec。

四、ASStackLayoutSpec(堆疊布局規則)

在AsyncDisplayKit的所有LayoutSpecs中,ASStackLayoutSpec是最強大的,ASStackLayoutSpec使用flexbox算法來确定其子節點的位置和大小,Flexbox旨在不同的螢幕尺寸上提供一緻統一的布局。在堆疊布局中,以垂直或水準堆疊對齊item,堆疊布局可以是另一堆疊布局的子布局,這使得可以使用ASStackLayoutSpec來建立任何布局。

ASStackLayoutSpec的屬性介紹如下:

  1. direction,主軸的方向,指定子項的堆疊方向,預設是縱向。
  2. spacing,每個子元素之間的距離,即主軸上視圖排列的間距。
  3. horizontalAlignment,水準對齊方式
  4. verticalAlignment,垂直對齊方式
  5. justifyContent,主軸上的排列方式,分五種:從前往後排列、居中排列、從後往前排列、間隔排列(兩端無間隔)、間隔排列(兩端有間隔)。
  6. alignItems,交叉軸上的排列方式
  7. flexWrap
  8. alignContent
  9. lineSpacing

Flexbox在ASDK中的工作方式與CSS在Web中的工作方式是相同的。

五、ASStackLayout布局元素屬性

僅針對ASStackLayoutSpec布局的元素有效。

Texture

六、ASLayout布局元素屬性

Texture

後記:本文隻是對ASDK做了一個簡單的介紹,通過本文可以對Texture有個初步了解,但是要想真正上手去做項目,還是要下一番功夫的,建議參考這篇文章:https://github.com/Luis-X/Facebook-Texture

以上。