本文来自尚妆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 | ... |