本文來自尚妝iOS團隊嘉文
發表於尚妝github博客,歡迎訂閱!html
原文連接 texturegroup.org/docs/gettin…node
AsyncDisplayKit是一個創建在UIKit基礎上的iOS框架,讓即便是最複雜的用戶界面光滑和響應。它最初建成Facebook的Paper應用,並與流行的pop基於物理的動畫相輔相成——它與UIKit動力學和傳統應用程序的設計一樣強大。最近,它是用於Pinterest應用的重寫。git
隨着框架的發展,添加了許多功能,在現代iOS應用程序中經過消除常見的樣板風格和結構能夠節省開發人員大量的時間。若是你曾經處理過Cell重用的Bug,試圖高性能預加載數據頁面或滾動風格界面,甚至只是試圖讓你的應用從降低太多的幀能夠受益於整合ASDK。github
官方地址objective-c
基本概念 | 英文 | 中文 |
---|---|---|
Layout Specs | specification | 佈局規則 |
Layout Elements | Elements | 佈局元素 |
一、LayoutSpecs(佈局規則)算法
LayoutSpecs是「layout specification」的縮寫,沒有物理存在。
相反,LayoutSpecs充當其餘LayoutElements的容器,來理解這些子LayoutElements如何相互關聯。
AsyncDisplayKit提供了ASLayoutSpec的幾個子類。
從插入單個簡單佈局規則到更多更復雜的佈局規則,變化堆放排列配置。複製代碼
二、LayoutElements(佈局元素)shell
LayoutSpecs包含並排列LayoutElements。 全部ASDisplayNodes和ASLayoutSpecs都符合協議。 這意味着您能夠從Nodes和其餘LayoutSpecs構成LayoutSpecs。 ASLayoutElement協議有幾個屬性,可用於建立很是複雜的LayoutSpecs。 此外LayoutSpecs也具備本身的一組屬性,可用於調整LayoutElements的排列。 複製代碼
三、組合LayoutSpecs和LayoutElements,建立複雜的UI服務器
能夠看到如何將ASTextNode(黃色高亮),ASVideoNode(頂部圖像)和ASStackLayoutSpec(「堆放佈局規則」)組合來建立複雜佈局。複製代碼
使用ASCenterLayoutSpec(「中心佈局規則」)和ASOverlayLayoutSpec(「覆蓋佈局規則」),來放置頂部ASVideoNode(頂部圖像)的播放按鈕。複製代碼
四、一些Node須要固定大小框架
#一些元素具備一個」固有大小「,基於他們可用內容。
例如,ASTextNode能夠根據其屬性字符串計算其大小,其餘具備固有大小的Node包括:
ASImageNode
ASTextNode
ASButtonNode
ASTextNode
#全部其餘Node在外部資源加載完成以前沒有或者缺少固有大小。
例如,在從URL下載圖像以前,ASNetworkImageNode不知道它的大小。這些種類包括:
ASVideoNode
ASVideoPlayerNode
ASNetworkImageNode
ASEditableTextNode
#注意:
#缺乏初始固有大小的這些Node必須設置它們的初始大小,使用ASRatioLayoutSpec(「比例佈局規則」),ASAbsoluteLayoutSpec(「絕對佈局規則」)或者對象的size屬性。複製代碼
五、Layout調試async
#在任何ASDisplayNode或ASLayoutSpec上調用-asciiArtString,會返回對象及其子對象的字符圖。
(可選)若是在任何Node或layoutSpec上設置.debugName,那麼也將包含在字符圖。
例如:
-----------------------ASStackLayoutSpec----------------------
| -----ASStackLayoutSpec----- -----ASStackLayoutSpec----- |
| | ASImageNode | | ASImageNode | |
| | ASImageNode | | ASImageNode | |
| --------------------------- --------------------------- |
--------------------------------------------------------------
#能夠在任何ASLayoutElement(node或layoutSpec)上打印對象樣式,調整大小屬性時極其方便。
例如:
(lldb) po _photoImageNode.style
Layout Size = min {414pt, 414pt} <= preferred="" {20%,="" 50%}="" <="max" {414pt,="" 414pt}<="" code="">
複製代碼
一、Simple Header with Left and Right Justified Text(簡單標題左右對齊)
建立佈局:
約束 | 說明 |
---|---|
ASStackLayoutSpec | 垂直的 |
ASStackLayoutSpec | 水平的 |
ASInsetLayoutSpec | 插入整個標題 |
佈局的組成(layout specs + nodes),如圖:
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
// 當用戶名和位置信息文本太長時,收縮堆放視圖來適應屏幕,而不是將全部內容向右堆放
ASStackLayoutSpec *nameLocationStack = [ASStackLayoutSpec verticalStackLayoutSpec];
nameLocationStack.style.flexShrink = 1.0;
nameLocationStack.style.flexGrow = 1.0;
//若是從服務器獲取位置信息,並檢查位置信息是否可用
if (_postLocationNode.attributedText) {
nameLocationStack.children = @[_usernameNode, _postLocationNode];
} else {
nameLocationStack.children = @[_usernameNode];
}
//水平堆放
ASStackLayoutSpec *headerStackSpec = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal
spacing:40
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter
children:@[nameLocationStack, _postTimeNode]];
//插入堆放
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(0, 10, 0, 10)
child:headerStackSpec];
}複製代碼
將示例項目從縱向旋轉到橫向,看看間隔體是如何增加和收縮的。
二、Photo with Inset Text Overlay(圖片上覆蓋文本)
建立佈局:
約束 | 說明 |
---|---|
ASInsetLayoutSpec | 插入文本 |
ASOverlayLayoutSpec | 插入文本覆蓋在圖片上 |
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
_photoNode.style.preferredSize = CGSizeMake(USER_IMAGE_HEIGHT*2, USER_IMAGE_HEIGHT*2);
// INIFINITY(插入無邊界)
UIEdgeInsets insets = UIEdgeInsetsMake(INFINITY, 12, 12, 12);
ASInsetLayoutSpec *textInsetSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:_titleNode];
return [ASOverlayLayoutSpec overlayLayoutSpecWithChild:_photoNode
overlay:textInsetSpec];
}複製代碼
三、Photo with Outset Icon Overlay(圖片上覆蓋和圖標)
建立佈局:
約束 | 說明 |
---|---|
ASAbsoluteLayoutSpec | 放置照片和icon |
ASLayoutable屬性 | 單獨調整大小和位置 |
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
_iconNode.style.preferredSize = CGSizeMake(40, 40);
_iconNode.style.layoutPosition = CGPointMake(150, 0);
_photoNode.style.preferredSize = CGSizeMake(150, 150);
_photoNode.style.layoutPosition = CGPointMake(40 / 2.0, 40 / 2.0);
return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithSizing:ASAbsoluteLayoutSpecSizingSizeToFit
children:@[_photoNode, _iconNode]];
}複製代碼
四、Simple Inset Text Cell(簡單插入文本單元格)
建立佈局:
約束 | 說明 |
---|---|
ASInsetLayoutSpec | 插入文本 |
ASCenterLayoutSpec | 根據指定屬性文本居中 |
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
UIEdgeInsets insets = UIEdgeInsetsMake(0, 12, 4, 4);
ASInsetLayoutSpec *inset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets
child:_titleNode];
return [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringY
sizingOptions:ASCenterLayoutSpecSizingOptionMinimumX
child:inset];
}複製代碼
五、Top and Bottom Separator Lines(頂部和底部分隔線)
建立佈局:
約束 | 說明 |
---|---|
ASInsetLayoutSpec | 插入文本 |
ASStackLayoutSpec | 垂直的堆放文本上下分割線 |
佈局的組成(layout specs + nodes),如圖:
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
_topSeparator.style.flexGrow = 1.0;
_bottomSeparator.style.flexGrow = 1.0;
ASInsetLayoutSpec *insetContentSpec = [ASInsetLayoutSpec insetLayoutSpecWithInsets:UIEdgeInsetsMake(20, 20, 20, 20) child:_textNode];
return [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical
spacing:0
justifyContent:ASStackLayoutJustifyContentCenter
alignItems:ASStackLayoutAlignItemsStretch
children:@[_topSeparator, insetContentSpec, _bottomSeparator]];
}複製代碼
一、如下ASLayoutSpec子類,用於組成簡單或複雜的佈局
佈局規則 | 說明 |
---|---|
ASInsetLayoutSpec | 插入佈局 |
ASOverlayLayoutSpec | 覆蓋佈局 |
ASBackgroundLayoutSpec | 背景佈局 |
ASCenterLayoutSpec | 中心佈局 |
ASRatioLayoutSpec | 比例佈局 |
ASStackLayoutSpec | 堆疊佈局 |
ASAbsoluteLayoutSpec | 絕對佈局 |
你能夠子類化ASLayoutSpec,自定義ASLayoutSpec
在佈局過程當中,ASInsetLayoutSpec經過constrainedSize.max傳遞插入減掉後的CGSize給子項,一旦子項肯定它的最終尺寸,插入規則將其最終尺寸加上其插入邊距向上傳遞,因爲插圖佈局規則的大小基於其子項的大小,因此子項必須具備固有大小或明確設置其大小。複製代碼
一、若是在UIEdgeInsets中設置了INFINITY做爲值,插入規則只使用子項固有大小。
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
...
UIEdgeInsets *insets = UIEdgeInsetsMake(10, 10, 10, 10);
ASInsetLayoutSpec *headerWithInset = insetLayoutSpecWithInsets:insets child:textNode];
...
}複製代碼
ASOverlayLayoutSpec佈局一個組件(紅色),做爲覆蓋伸展到另個組件(藍色)以前覆蓋佈局的大小,是根據子項的大小計算得出的。下圖中,子項是藍色層,而後子項的大小做爲constrainedSize傳遞給覆蓋佈局元素(紅色層),子項(藍色層)必須具備固有大小或在其上設置的大小。複製代碼
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor blueColor]);
ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]
return [ASOverlayLayoutSpec overlayLayoutSpecWithChild:backgroundNode overlay:foregroundNode]];
}複製代碼
ASBackgroundLayoutSpec佈局一個組件(紅色),做爲背景伸展到另外一個組件(藍色)以後背景佈局的大小,是根據子項的大小計算得出的。下圖中,子項是藍色層,而後,子項的大小做爲constrainedSize傳遞給背景佈局元素(紅色層),子項(藍色層)必須具備固有大小或在其上設置的大小。複製代碼
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
ASDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor blueColor]);
return [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:foregroundNode background:backgroundNode]];
}複製代碼
ASCenterLayoutSpec將其子項居中在其最大值中constrainedSize。
若是中心規格的寬度或高度不受約束,它會縮小到子項的大小。複製代碼
ASCenterLayoutSpec的兩個屬性:
屬性 | 說明 | 值 |
---|---|---|
centeringOptions | 肯定中心位置 | None,X,Y,XY |
sizingOptions | 肯定中心佔用空間 | Default,minimum X,minimum Y,minimum XY |
代碼:
//Objective-C
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
ASStaticSizeDisplayNode *subnode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], CGSizeMake(70, 100));
return [ASCenterLayoutSpec centerLayoutSpecWithCenteringOptions:ASCenterLayoutSpecCenteringXY
sizingOptions:ASRelativeLayoutSpecSizingOptionDefault
child:subnode]
}複製代碼
ASRatioLayoutSpec佈局縮放固定寬高比,此規則必須具備做爲constrainedSize傳遞給它的寬度或高度,由於它使用此值來縮放自身。
使用比例佈局爲ASNetworkImageNode或ASVideoNode提供固有大小是很是常見的,由於二者在服務器返回內容以前都沒有內在大小。複製代碼
代碼:
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
//一半比例
ASStaticSizeDisplayNode *subnode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], CGSizeMake(100, 100));
return [ASRatioLayoutSpec ratioLayoutSpecWithRatio:0.5 child:subnode];
}複製代碼
根據垂直和水平位置說明範圍內佈局組件,子項能夠被定位在4個角中的任何一個,或者4個邊緣中的任何一個,以及中心。複製代碼
代碼:
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
...
ASDisplayNode *backgroundNode = ASDisplayNodeWithBackgroundColor([UIColor redColor]);
ASStaticSizeDisplayNode *foregroundNode = ASDisplayNodeWithBackgroundColor([UIColor greenColor], CGSizeMake(70, 100));
ASRelativeLayoutSpec *relativeSpec = [ASRelativeLayoutSpec relativePositionLayoutSpecWithHorizontalPosition:ASRelativeLayoutSpecPositionStart
verticalPosition:ASRelativeLayoutSpecPositionStart
sizingOption:ASRelativeLayoutSpecSizingOptionDefault
child:foregroundNode]
ASBackgroundLayoutSpec *backgroundSpec = [ASBackgroundLayoutSpecbackgroundLayoutSpecWithChild:relativeSpec background:backgroundNode];
...
}複製代碼
在ASDK中的全部layoutSpecs中,ASStackLayoutSpec是很是強大的,ASStackLayoutSpec使用flexbox算法來肯定其子節點的位置和大小,Flexbox旨在在不一樣的屏幕尺寸上提供一致的佈局,在堆疊佈局中,以垂直或水平堆疊對齊item。堆疊佈局能夠是另外一個堆疊佈局的子佈局,這使得可使用堆疊佈局規則建立幾乎任何佈局。複製代碼
ASStackLayoutSpec除了ASLayoutElement還有7個屬性:
屬性 | 說明 | 描述 |
---|---|---|
direction | 方向 | 指定堆疊方向,若是設置了horizontalAlignment和verticalAlignment,它們將被再次解決,致使justifyContent和alignItems被相應地更新。 |
spacing | 間距 | 每一個子元素之間的距離。 |
horizontalAlignment | 水平對齊 | 指定子元素如何水平排列,取決於堆疊方向,設置對齊會致使justifyContent或alignItems被更新。將來方向更改後,對齊將保持有效。所以,優選那些性質。 |
verticalAlignment | 豎直對齊 | 指定子元素如何垂直排列,取決於堆疊方向,設置對齊會致使justifyContent或alignItems被更新。將來方向更改後,對齊將保持有效。所以,優選那些性質。 |
justifyContent | 對齊內容 | 每一個子元素之間的距離。 |
alignItems | 對齊Item | 子元素沿着橫軸的方向。 |
baselineRelativeArrangement | 基線相對佈局 | 若是YES,則從頂視圖的最後基線到底視圖的頂部測量兩個視圖之間的垂直間距。 |
代碼:
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
ASStackLayoutSpec *mainStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionHorizontal spacing:6.0
justifyContent:ASStackLayoutJustifyContentStart
alignItems:ASStackLayoutAlignItemsCenter
children:@[_iconNode, _countNode]];
//設置一些大小約束
mainStack.minWidth = ASDimensionMakeWithPoints(60.0);
mainStack.maxHeight = ASDimensionMakeWithPoints(40.0);
return mainStack;
}複製代碼
說明:
Flexbox在AsyncDisplayKit中的工做方式與在Web上的CSS中的工做方式相同,有一些例外。
默認值不一樣,沒有flex參數,flexGrow和flexShrink只支持一個布爾值。
在ASAbsoluteLayoutSpec中,能夠經過設置其layoutPosition屬性來指定其子元素的確切位置(x / y座標),絕對佈局比其餘類型的佈局更不靈活和難以維護。複製代碼
ASAbsoluteLayoutSpec屬性:
屬性 | 說明 | 值 |
---|---|---|
sizing | 大小 | Default / Size to Fit |
肯定絕對規格將佔用多少空間。
注意:Size to Fit選項將複製舊的ASStaticLayoutSpec行爲。
代碼:
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
CGSize maxConstrainedSize = constrainedSize.max;
//在靜態佈局中佈局全部Node
guitarVideoNode.layoutPosition = CGPointMake(0, 0);
guitarVideoNode.size = ASSizeMakeFromCGSize(CGSizeMake(maxConstrainedSize.width, maxConstrainedSize.height / 3.0));
nicCageVideoNode.layoutPosition = CGPointMake(maxConstrainedSize.width / 2.0, maxConstrainedSize.height / 3.0);
nicCageVideoNode.size = ASSizeMakeFromCGSize(CGSizeMake(maxConstrainedSize.width / 2.0, maxConstrainedSize.height / 3.0));
simonVideoNode.layoutPosition = CGPointMake(0.0, maxConstrainedSize.height - (maxConstrainedSize.height / 3.0));
simonVideoNode.size = ASSizeMakeFromCGSize(CGSizeMake(maxConstrainedSize.width/2, maxConstrainedSize.height / 3.0));
hlsVideoNode.layoutPosition = CGPointMake(0.0, maxConstrainedSize.height / 3.0);
hlsVideoNode.size = ASSizeMakeFromCGSize(CGSizeMake(maxConstrainedSize.width / 2.0, maxConstrainedSize.height / 3.0));
return [ASAbsoluteLayoutSpec absoluteLayoutSpecWithChildren:@[guitarVideoNode, nicCageVideoNode, simonVideoNode, hlsVideoNode]];
}複製代碼
ASLayoutSpec是全部佈局規則都被子類化的父類,它的主要工做是處理和管理全部的子類,但它也能夠用於建立自定義佈局規格,只有超級高級應該但願/須要建立ASLayoutSpec的自定義子類。相反,嘗試使用提供的佈局規則,並將它們組合在一塊兒以建立更高級的佈局。複製代碼
ASLayoutSpec的另外一個用途是充當ASStackLayoutSpec中的其餘子元素,在使用.flexGrow和/或.flexShrink時。
代碼:
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize{
...
// ASLayoutSpec做爲間隔
let spacer = ASLayoutSpec()
spacer.flexGrow = true
stack.children = [imageNode, spacer, textNode]
...
}複製代碼
屬性 | 說明 |
---|---|
ASStackLayoutElement Properties | 只對stack堆疊佈局的Node生效 |
ASAbsoluteLayoutElement Properties | 只對absolute絕對佈局的Node生效 |
ASLayoutElement Properties | 對全部佈局和Node生效 |
屬性 | 類型 | 描述 |
---|---|---|
.style.spacingBefore | CGFloat | 在堆疊方向上放置此對象以前的額外空間。 |
.style.spacingAfter | CGFloat | 在堆疊方向上放置此對象以後的額外空間。 |
.style.flexGrow | BOOL | 若是子元素的堆疊大小的總和小於最小大小,那麼這個對象是否增加? |
.style.flexShrink | BOOL | 若是子元素的堆疊大小的總和大於最大大小,那麼這個對象是否縮小? |
.style.flexBasis | ASDimension | 使用flexGrow或flexShrink屬性並分配剩餘空間以前,在堆棧維度(水平或垂直)中指定此對象的初始大小。 |
.style.alignSelf | ASStackLayoutAlignSelf | 沿着橫軸的對象的方向,覆蓋alignItems。(ASStackLayoutAlignSelfAuto,ASStackLayoutAlignSelfStart, ASStackLayoutAlignSelfEnd, ASStackLayoutAlignSelfCenter, ASStackLayoutAlignSelfStretch) |
.style.ascender | CGFloat | 用於基線對準。從對象的頂部到其基線的距離。 |
.style.descender | CGFloat | 用於基線對準。從對象的底部部到其基線的距離 |
屬性 | 類型 | 描述 |
---|---|---|
.style.layoutPosition | CGPoint | 該對象在ASAbsoluteLayoutSpec父規則中的CGPoint位置。 |
屬性 | 類型 | 描述 |
---|---|---|
.style.width | ASDimension | 設置元素的寬度。 會被minWidth和maxWidth覆蓋。默認爲ASDimensionAuto |
.style.height | ASDimension | 設置元素的高度。 會被minHeight和maxHeight覆蓋。默認爲ASDimensionAuto。 |
.style.minHeight | ASDimension | 設置元素的最大高度。 它防止height屬性的已使用值變得大於爲maxHeight指定的值。 maxHeight的值覆蓋height,但minHeight覆蓋maxHeight。默認爲ASDimensionAuto |
.style.maxHeight | ASDimension | 若是子元素的堆棧大小的總和大於最大大小,那麼這個對象是否應該縮小呢? |
.style.minWidth | ASDimension | 設置元素的最小寬度。它防止width屬性的使用值變得小於爲minWidth指定的值。 minWidth的值覆蓋maxWidth和width。默認爲ASDimensionAuto |
.style.maxWidth | ASDimension | 設置元素的最大寬度。 它防止width屬性的使用值變得大於爲maxWidth指定的值。 maxWidth的值覆蓋width,但minWidth覆蓋maxWidth。默認爲ASDimensionAuto |
.style.preferredSize | CGSize | 提供佈局元素的建議大小。 若是提供了可選的minSize或maxSize,且preferredSize超過這些,則將強制執行minSize或maxSize, 若是未提供此可選值,則佈局元素的大小將默認爲其提供的內在內容大小calculateSizeThatFits: |
.style.minSize | CGSize | |
.style.maxSize | CGSize | |
.style.preferredLayoutSize | ASLayoutSize | |
.style.minLayoutSize | ASLayoutSize | |
.style.maxLayoutSize | ASLayoutSize | ... |