Texture 佈局篇

image

Texture 擁有自己的一套成熟佈局方案,雖然學習成本略高,但至少比原生的 AutoLayout 寫起來舒服,重點是性能遠好於 AutoLayoutTexture 文檔上也指出了這套佈局方案的的優點:

  • Fast: As fast as manual layout code and significantly faster than Auto Layout
  • Asynchronous & Concurrent: Layouts can be computed on background threads so user interactions are not interrupted.
  • Declarative: Layouts are declared with immutable data structures. This makes layout code easier to develop, document, code review, test, debug, profile, and maintain.
  • Cacheable: Layout results are immutable data structures so they can be precomputed in the background and cached to increase user perceived performance.
  • Extensible: Easy to share code between classes.

首先這套佈局都是基於 Texture 組件的,所以當遇到要使用原生控件時,通過用 block 的方式包裝一個原生組件再合適不過了,例如:

ASDisplayNode *animationImageNode = [[ASDisplayNode alloc] initWithViewBlock:^UIView * _Nonnull{
    FLAnimatedImageView *animationImageView = [[FLAnimatedImageView alloc] init];
    animationImageView.layer.cornerRadius = 2.0f;
    animationImageView.clipsToBounds = YES;
    return animationImageView;
}];
[self addSubnode:animationImageNode];
self.animationImageNode = animationImageNode;

ASDisplayNode 在初始化之後會檢查是否有子視圖,如果有就會調用

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize

方法進行佈局,所以對視圖進行佈局需要重寫這個方法。看一個例子:

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    ASInsetLayoutSpec *inset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:_childNode];
    return insetLayout;
}

_childNode 相對於父視圖邊距都爲 0,也就是AutoLayouttop bottom left right 都爲 0。

-----------------------------父視圖----------------------------
|  -------------------------_childNode---------------------  |
|  |                                                      |  |
|  |                                                      |  |
|  ---------------------------  ---------------------------  |
--------------------------------------------------------------

可以看到layoutSpecThatFits:方法返回的必須是 ASLayoutSpec, ASInsetLayoutSpec 是它的子類之一,下面是所有的子類及其關係:

  • ASLayoutSpec

    • ASAbsoluteLayoutSpec // 絕對佈局
    • ASBackgroundLayoutSpec // 背景佈局
    • ASInsetLayoutSpec // 邊距佈局
    • ASOverlayLayoutSpec // 覆蓋佈局
    • ASRatioLayoutSpec // 比例佈局
    • ASRelativeLayoutSpec // 頂點佈局

      • ASCenterLayoutSpec // 居中佈局
    • ASStackLayoutSpec // 盒子佈局
    • ASWrapperLayoutSpec // 填充佈局
    • ASCornerLayoutSpec // 角標佈局

_

ASAbsoluteLayoutSpec

使用方法和原生的絕對佈局類似

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
  self.childNode.style.layoutPosition = CGPointMake(100, 100);
  self.childNode.style.preferredLayoutSize = ASLayoutSizeMake(ASDimensionMake(100), ASDimensionMake(100));

  ASAbsoluteLayoutSpec *absoluteLayout = [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[self.childNode]];
  return absoluteLayout;
}

值得提的是:ASAbsoluteLayoutSpec 一般情況都會通過 ASOverlayLayoutSpecASOverlayLayoutSpec 着陸,因爲只有上述兩種佈局才能保留 ASAbsoluteLayoutSpec 絕對佈局的事實。舉個例子當視圖中只有一個控件需要用的是 ASAbsoluteLayoutSpec 佈局,而其他控件佈局用的是 ASStackLayoutSpec(後面會介紹),那麼一旦 absoluteLayout 被加入到 ASStackLayoutSpec 也就失去它原本的佈局的意義。

ASOverlayLayoutSpec *contentLayout = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:stackLayout overlay:absoluteLayout];

不過官方文檔明確指出應該儘量少用這種佈局方式:

Absolute layouts are less flexible and harder to maintain than other types of layouts.

_

ASBackgroundLayoutSpec

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
  ASBackgroundLayoutSpec *backgroundLayout = [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:self.childNodeB background:self.childNodeA];
  return backgroundLayout;
}

childNodeA 做爲 childNodeB 的背景,也就是 childNodeB 在上層,要注意的是 ASBackgroundLayoutSpec 事實上根本不會改變視圖的層級關係,比如:

ASDisplayNode *childNodeB = [[ASDisplayNode alloc] init];
childNodeB.backgroundColor = [UIColor blueColor];
[self addSubnode:childNodeB];
self.childNodeB = childNodeB;

ASDisplayNode *childNodeA = [[ASDisplayNode alloc] init];
childNodeA.backgroundColor = [UIColor redColor];
[self addSubnode:childNodeA];
self.childNodeA = childNodeA;

那麼即使使用上面的佈局方式,childNodeB 依然在下層。

_

ASInsetLayoutSpec

比較常用的一個類,看圖應該能一目瞭然(圖片來自於官方文檔
image

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    ASInsetLayoutSpec *inset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsZero child:_childNode];
    return insetLayout;
}

_childNode 相對於父視圖邊距都爲 0,相當於填充整個父視圖。它和之後會說到的
ASOverlayLayoutSpec 實際上更多的用來組合兩個 Element 而已。

_

ASOverlayLayoutSpec

參考 ASBackgroundLayoutSpec

_

ASRatioLayoutSpec

image(圖片來自於官方文檔

也是比較常用的一個類,作用是設置自身的高寬比,例如設置正方形的視圖

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    ASRatioLayoutSpec *ratioLayout = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:1.0f child:self.childNodeA];
    return ratioLayout;
}

_

ASRelativeLayoutSpec

把它稱爲頂點佈局可能有點不恰當,實際上它可以把視圖佈局在:左上左下右上右下四個頂點以外,還可以設置成居中佈局。

image

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    self.childNodeA.style.preferredSize = CGSizeMake(100, 100);
    ASRelativeLayoutSpec *relativeLayout = [ASRelativeLayoutSpec relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionEnd verticalPosition:ASRelativeLayoutSpecPositionStart sizingOption:ASRelativeLayoutSpecSizingOptionDefault child:self.childNodeA];
    return relativeLayout;
}

上面的例子就是把 childNodeA 顯示在右上角。

_

ASCenterLayoutSpec

絕大多數情況下用來居中顯示視圖

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    self.childNodeA.style.preferredSize = CGSizeMake(100, 100);
    ASCenterLayoutSpec *relativeLayout = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:self.childNodeA];
    return relativeLayout;
}

_

ASStackLayoutSpec

可以說這是最常用的類,而且相對於其他類來說在功能上是最接近於 AutoLayout 的。
之所以稱之爲盒子佈局是因爲它和 CSS 中 Flexbox 很相似,關於 Flexbox 的可以看下阮一峯的這篇文章

先看一個例子:

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    self.childNodeA.style.preferredSize = CGSizeMake(100, 100);
    self.childNodeB.style.preferredSize = CGSizeMake(200, 200);
    ASStackLayoutSpec *stackLayout = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
                                                                             spacing:12
                                                                      justifyContent:ASStackLayoutJustifyContentStart
                                                                          alignItems:ASStackLayoutAlignItemsStart
                                                                            children:@[self.childNodeA, self.childNodeB]];
    return stackLayout;
}

簡單的說明下各個參數的作用:

  1. direction:主軸的方向,有兩個可選值:
  • 縱向:ASStackLayoutDirectionVertical
  • 橫向:ASStackLayoutDirectionHorizontal
  1. spacing: 主軸上視圖排列的間距,比如有四個視圖,那麼它們之間的存在三個間距值都應該是spacing
  2. justifyContent: 主軸上的排列方式,有五個可選值:
  • ASStackLayoutJustifyContentStart 從前往後排列
  • ASStackLayoutJustifyContentCenter 居中排列

    • ASStackLayoutJustifyContentEnd 從後往前排列
    • ASStackLayoutJustifyContentSpaceBetween 間隔排列,兩端無間隔
    • ASStackLayoutJustifyContentSpaceAround 間隔排列,兩端有間隔
  1. alignItems: 交叉軸上的排列方式,有五個可選值:
  • ASStackLayoutAlignItemsStart 從前往後排列
  • ASStackLayoutAlignItemsEnd 從後往前排列

    • ASStackLayoutAlignItemsCenter 居中排列
    • ASStackLayoutAlignItemsStretch 拉伸排列
    • ASStackLayoutAlignItemsBaselineFirst 以第一個文字元素基線排列(主軸是橫向纔可用)
    • ASStackLayoutAlignItemsBaselineLast 以最後一個文字元素基線排列(主軸是橫向纔可用)
  1. children: 包含的視圖。數組內元素順序同樣代表着佈局時排列的順序,所以需要注意

主軸的方向設置尤爲重要,如果主軸設置的是 ASStackLayoutDirectionVertical, 那麼 justifyContent 各個參數的意義就是:

  • ASStackLayoutJustifyContentStart 從上往下排列
  • ASStackLayoutJustifyContentCenter 居中排列
  • ASStackLayoutJustifyContentEnd 從下往上排列
  • ASStackLayoutJustifyContentSpaceBetween 間隔排列,兩端無間隔
  • ASStackLayoutJustifyContentSpaceAround 間隔排列,兩端有間隔

alignItems 就是:

  • ASStackLayoutAlignItemsStart 從左往右排列
  • ASStackLayoutAlignItemsEnd 從右往左排列
  • ASStackLayoutAlignItemsCenter 居中排列
  • ASStackLayoutAlignItemsStretch 拉伸排列
  • ASStackLayoutAlignItemsBaselineFirst 無效
  • ASStackLayoutAlignItemsBaselineLast 無效

對於子視圖間距不一樣的佈局方法,後面實戰中會講到。

_

ASWrapperLayoutSpec

填充整個視圖

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{    
    ASWrapperLayoutSpec *wrapperLayout = [ASWrapperLayoutSpec wrapperWithLayoutElement:self.childNodeA];
    return wrapperLayout;
}

ASCornerLayoutSpec

顧名思義 ASCornerLayoutSpec 適用於類似於角標的佈局

override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec
{
  let cornerSpec = ASCornerLayoutSpec(child: avatarNode, corner: badgeNode, location: .topRight)
  cornerSpec.offset = CGPoint(x: -3, y: 3)
}

最需要注意的是offset是控件的Center的偏移

佈局實戰

案例一

image

簡單的文件覆蓋在圖片上,文字居中。

- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    ASWrapperLayoutSpec *wrapperLayout = [ASWrapperLayoutSpec wrapperWithLayoutElement:self.coverImageNode];

    ASCenterLayoutSpec *centerSpec = [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY sizingOptions:ASCenterLayoutSpecSizingOptionDefault child:self.textNode];
    ASOverlayLayoutSpec *overSpec = [ASOverlayLayoutSpec overlayLayoutSpecWithChild:wrapperLayout overlay:centerSpec];
    return overSpec;
}
  1. ASWrapperLayoutSpec 把圖片鋪滿整個視圖
  2. ASCenterLayoutSpec 把文字居中顯示
  3. ASOverlayLayoutSpec 把文字覆蓋到圖片上

注意第三步就是之前提到的 ASOverlayLayoutSpec/ASBackgroundLayoutSpec 的作用:用於組合兩個 Element

案例二

image

這個是輕芒閱讀(豌豆莢一覽) APP 內 AppSo 頻道 Cell 的佈局,應該也是比較典型的佈局之一。爲了方便理解先給各個元素定一下名稱,從上至下,從左往右分別是:

  • coverImageNode // 大圖
  • titleNode // 標題
  • subTitleNode // 副標題
  • dateTextNode // 發佈時間
  • shareImageNode // 分享圖標
  • shareNumberNode // 分享數量
  • likeImageNode // 喜歡圖標
  • likeNumberNode // 喜歡數量
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
    
    
    self.shareImageNode.style.preferredSize = CGSizeMake(15, 15);
    self.likeImageNode.style.preferredSize = CGSizeMake(15, 15);
    
    ASStackLayoutSpec *likeLayout = [ASStackLayoutSpec horizontalStackLayoutSpec];
    likeLayout.spacing = 4.0;
    likeLayout.justifyContent = ASStackLayoutJustifyContentStart;
    likeLayout.alignItems = ASStackLayoutAlignItemsCenter;
    likeLayout.children = @[self.likeImageNode, self.likeNumberNode];
    
    ASStackLayoutSpec *shareLayout = [ASStackLayoutSpec horizontalStackLayoutSpec];
    shareLayout.spacing = 4.0;
    shareLayout.justifyContent = ASStackLayoutJustifyContentStart;
    shareLayout.alignItems = ASStackLayoutAlignItemsCenter;
    shareLayout.children = @[self.shareImageNode, self.shareNumberNode];
    
    ASStackLayoutSpec *otherLayout = [ASStackLayoutSpec horizontalStackLayoutSpec];
    otherLayout.spacing = 12.0;
    otherLayout.justifyContent = ASStackLayoutJustifyContentStart;
    otherLayout.alignItems = ASStackLayoutAlignItemsCenter;
    otherLayout.children = @[likeLayout, shareLayout];
    
    ASStackLayoutSpec *bottomLayout = [ASStackLayoutSpec horizontalStackLayoutSpec];
    bottomLayout.justifyContent = ASStackLayoutJustifyContentSpaceBetween;
    bottomLayout.alignItems = ASStackLayoutAlignItemsCenter;
    bottomLayout.children = @[self.dateTextNode, otherLayout];
    
    self.titleNode.style.spacingBefore = 12.0f;
    
    self.subTitleNode.style.spacingBefore = 16.0f;
    self.subTitleNode.style.spacingAfter = 20.0f;
    
    ASRatioLayoutSpec *rationLayout = [ASRatioLayoutSpec ratioLayoutSpecWithRatio:0.5 child:self.coverImageNode];
    
    ASStackLayoutSpec *contentLayout = [ASStackLayoutSpec horizontalStackLayoutSpec];
    contentLayout.justifyContent = ASStackLayoutJustifyContentStart;
    contentLayout.alignItems = ASStackLayoutAlignItemsStretch;
    contentLayout.children = @[
                               rationLayout,
                               self.titleNode,
                               self.subTitleNode,
                               bottomLayout
                               ];
    
    ASInsetLayoutSpec *insetLayout = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(16, 16, 16, 16) child:contentLayout];
    return insetLayout;
}

下面詳細解釋下佈局,不過首先要明確的是,Texture 的這套佈局方式遵守從裏到外的佈局原則,使用起來纔會得心應手。

  1. 根據佈局的原則,首先利用 ASStackLayoutSpec 佈局 分享圖標分享數量喜歡圖標喜歡數量
  2. 還是通過 ASStackLayoutSpec 包裝第一步的兩個的佈局得到 otherLayout 佈局對象。
  3. 依然是 ASStackLayoutSpec 包裝otherLayout發佈時間。注意這裏設置橫向的排列方式 ASStackLayoutJustifyContentSpaceBetween已到達兩端佈局的目的,最終返回 bottomLayout
  4. 由於 大圖 是網絡圖片,對於 Cell 來說,子視圖的佈局必能能決定其高度(Cell 寬度是默認等於 TableNode 的寬度),所以這裏必須設置 大圖 的高度,ASRatioLayoutSpec 設置了圖片的高寬比。
  5. 接下來佈局應該就是 大圖標題副標題bottomLayout 的一個縱向佈局,可以發現這裏的視圖間距並不相同,這時候 spacingBeforespacingAfter 就會很有用,它們用來分別設置元素在主軸上的前後間距。self.titleNode.style.spacingBefore = 12.0f; 意思就是 標題 相對於 大圖 間距爲 12。
  6. 最後通過一個 ASInsetLayoutSpec 設置一個邊距。

可以看到不僅是 NodeASLayoutSpec 本身也可以作爲佈局元素,這是因爲只要是遵守了 <ASLayoutElement> 協議的對象都可以作爲佈局元素。

案例三

image

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
        
        self.node1.style.preferredSize = CGSize(width: constrainedSize.max.width, height: 136)
        
        
        self.node2.style.preferredSize = CGSize(width: 58, height: 25)
        self.node2.style.layoutPosition = CGPoint(x: 14.0, y: 95.0)
        
        self.node3.style.height = ASDimensionMake(37.0)
        self.node4.style.preferredSize = CGSize(width: 80, height: 20)
        self.node5.style.preferredSize = CGSize(width: 80, height: 20)
        
        self.node4.style.spacingBefore = 14.0
        self.node5.style.spacingAfter = 14.0
        
        let absoluteLayout = ASAbsoluteLayoutSpec(children: [self.node2])
        
        let overlyLayout = ASOverlayLayoutSpec(child: self.node1, overlay: absoluteLayout)
        
        let insetLayout = ASInsetLayoutSpec(insets: UIEdgeInsetsMake(0, 14, 0, 14), child: self.node3)
        insetLayout.style.spacingBefore = 13.0
        insetLayout.style.spacingAfter = 25.0
        
        
        let bottomLayout = ASStackLayoutSpec.horizontal()
        bottomLayout.justifyContent = .spaceBetween
        bottomLayout.alignItems = .start
        bottomLayout.children = [self.node4, self.node5]
        bottomLayout.style.spacingAfter = 10.0
//        bottomLayout.style.width = ASDimensionMake(constrainedSize.max.width)
        
        
        let stackLayout = ASStackLayoutSpec.vertical()
        stackLayout.justifyContent = .start
        stackLayout.alignItems = .stretch
        stackLayout.children = [overlyLayout, insetLayout, bottomLayout]
        
        return stackLayout
    }

爲了演示 ASAbsoluteLayoutSpec 的使用,這裏 node3 我們用 ASAbsoluteLayoutSpec 佈局。

接下來說下要點:

  1. node 和 layoutSpec 都可以設置 style 屬性,因爲它們都準守 ASLayoutElement 協議
  2. 當 spaceBetween 沒有達到兩端對齊的效果,嘗試設置當前 layoutSpec 的 width(如註釋)或它的上一級佈局對象的 alignItems,在例子中就是 stackLayout.alignItems = .stretch
  3. ASAbsoluteLayoutSpec 必須有落點(除非是隻有絕對佈局),例子中 ASAbsoluteLayoutSpec 着落點就在 ASOverlayLayoutSpec

案例四

image

此案例主要爲了演示 flexGrow 的用法,先介紹下 flexGrow 的作用(來自於簡書九彩拼盤

該屬性來設置,當父元素的寬度大於所有子元素的寬度的和時(即父元素會有剩餘空間),子元素如何分配父元素的剩餘空間。

flex-grow的默認值爲0,意思是該元素不索取父元素的剩餘空間,如果值大於0,表示索取。值越大,索取的越厲害。舉個例子:

父元素寬400px,有兩子元素:A和B。A寬爲100px,B寬爲200px,則空餘空間爲 400-(100+200)= 100px。

如果A,B都不索取剩餘空間,則有100px的空餘空間。

如果A索取剩餘空間:設置flex-grow爲1,B不索取。則最終A的大小爲 自身寬度(100px)+ 剩餘空間的寬度(100px)= 200px

如果A,B都設索取剩餘空間,A設置flex-grow爲1,B設置flex-grow爲2。則最終A的大小爲 自身寬度(100px)+ A獲得的剩餘空間的寬度(100px (1/(1+2))),最終B的大小爲 自身寬度(200px)+ B獲得的剩餘空間的寬度(100px (2/(1+2)))

     override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
        
        self.node1.style.height = ASDimensionMake(20.0)
        var imageLayoutArray = [ASLayoutElement]()
        
        [self.node2, self.node3, self.node4].forEach { (node) in
            let layout = ASRatioLayoutSpec(ratio: 2.0/3.0, child: node)
            layout.style.flexGrow = 1 // 相當於寬度相等
            imageLayoutArray.append(layout)
        }
        
        let imageLayout = ASStackLayoutSpec.horizontal()
        imageLayout.justifyContent = .start
        imageLayout.alignItems = .start
        imageLayout.spacing = 14.0
        imageLayout.children = imageLayoutArray
        
        let contentLayout = ASStackLayoutSpec.vertical()
        contentLayout.justifyContent = .start
        contentLayout.alignItems = .stretch
        contentLayout.spacing = 22.0
        contentLayout.children = [self.node1, imageLayout]
        
        return ASInsetLayoutSpec(insets: UIEdgeInsetsMake(22.0, 16.0, 22.0, 16.0), child: contentLayout)
    }

在這個案例中 node2、node3、node4 的寬度的總和小於父元素的寬度,所以爲了達到寬度相同只需要設置三者的 flexGrow 相同就行(都爲1),再通過 ASRatioLayoutSpec 固定各自的寬高比,那麼對於這個三個控件來說最終的寬度是確定的。

案例四

image

此案例主要爲了演示 flexShrink 的用法,同樣還來自於簡書九彩拼盤關於 flexShrink 的介紹

該屬性來設置,當父元素的寬度小於所有子元素的寬度的和時(即子元素會超出父元素),子元素如何縮小自己的寬度的。

flex-shrink的默認值爲1,當父元素的寬度小於所有子元素的寬度的和時,子元素的寬度會減小。值越大,減小的越厲害。如果值爲0,表示不減小。

舉個例子:父元素寬400px,有兩子元素:A和B。A寬爲200px,B寬爲300px。則A,B總共超出父元素的寬度爲(200+300)- 400 = 100px。

如果A,B都不減小寬度,即都設置flex-shrink爲0,則會有100px的寬度超出父元素。如果A不減小寬度:設置flex-shrink爲0,B減小。則最終B的大小爲 自身寬度(300px)- 總共超出父元素的寬度(100px)= 200px如果A,B都減小寬度,A設置flex-shirk爲3,B設置flex-shirk爲2。則最終A的大小爲 自身寬度(200px)- A減小的寬度(100px (200px 3/(200 3 + 300 2))) = 150px,最終B的大小爲 自身寬度(300px)- B減小的寬度(100px (300px 2/(200 3 + 300 2))) = 250px

目前關於該屬性最常見還是用於對文本的寬度限制,在上圖中 textNode 和 displayNode 是兩端對齊,而且需要限制文本的最大寬度,這時候設置 flexShrink 是最方便的。

override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
        self.displayNode.style.preferredSize = CGSize(width: 42.0, height: 18.0)
        self.textNode.style.flexShrink = 1
        
        let contentLayout = ASStackLayoutSpec.horizontal()
        contentLayout.justifyContent = .spaceBetween
        contentLayout.alignItems = .start
        contentLayout.children = [self.textNode, self.displayNode]
        
        let insetLayout = ASInsetLayoutSpec(insets: UIEdgeInsetsMake(16.0, 16.0, 16.0, 16.0), child: contentLayout)
        
        return insetLayout
        
    }

隨便提一下的是如果 ASTextNode 出現莫名的文本截斷問題,可以用 ASTextNode2 代替。

案例五

還算比較典型的例子

image

override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {

        let otherLayout = ASInsetLayoutSpec(insets: UIEdgeInsetsMake(10.0, 10.0, CGFloat(Float.infinity), CGFloat(Float.infinity)), child: topLeftNode)
        
        let contentLayout = ASOverlayLayoutSpec(child: coverImageNode, overlay: otherLayout)
        return contentLayout
    }

利用 ASInsetLayoutSpec 是最好的解決方案,值得注意的是對於紅色控件只需要設置向上和向左的間距,那麼其他方向的可以用 CGFloat(Float.infinity) 代替,並不需要給出具體數值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章