节点容器

在容器中使用Nodes

AsyncDisplayKit有以下几种 Container

ASDK Node Container UIKit Equivalent
ASCollectionNode 代替UIKit的 UICollectionView
ASPagerNode 代替UIKit的 UIPageViewController
ASTableNode 代替UIKit的 UITableView
ASViewController 代替UIKit的 UIViewController
ASNavigationControllerv 代替UIKit的 UINavigationController,遵循ASVisibility协议
ASTabBarController 代替UIKit的 UITabBarController,遵循ASVisibility协议

Node Container的优势

Node Container可以自动地管理node的智能预加载,它会保证node的的布局计算、数据获取、解码和渲染会以异步的方式进行。

Node的子类

AsyncDisplayKit提供了以下几种node

相对UIKit的组件来说 node 最大的改进就是将所有布局和显示都放在子线程,因此主线程就能够即时地响应各种事件。

ASDK Node UIKit Equivalent
ASDisplayNode 代替UIKit的 UIView ,其他的node都继承于它
ASCellNode 代替UIKit的 UITableViewCellUICollectionViewCell,用在 ASTableNode , ASCollectionNodeASPagerNode
ASScrollNode 代替UIKit的 UIScrollView,这个 node 用在自定义滚动区域上非常有用
ASEditableTextNode 代替UIKit的 UITextView
ASTextNode 代替UIKit的 UILabel
ASImageNode 代替UIKit的 UIImage
ASNetworkImageNode
ASMultiplexImageNode
ASVideoNode 代替UIKit的 AVPlayerLayer
ASVideoPlayerNode 代替UIKit的 UIMoviePlayer
SControlNode 代替UIKit的 UIControl
ASButtonNode 代替UIKit的 UIButton
ASMapNode 代替UIKit的 MKMapView

AsyncDisplayKit 中的 node 相比UIKit中的组件更先进而且更方便。比如 ASNetworkImageNode 可以自动地加载和进行内存管理,而且还支持逐步加载Jpeg和动态gif图片。

node 的层级结构如下

Node的层级结构

上图中蓝色高亮的node是对UIKit元素的封装而成。比如 ASScrollNode 封装自 UIScrollViewASCollectionNode 封装自 UICollectionViewASMapNode 在实时地图模式中就是 UIMapView 封装。

基本重载方法

创建子类时,子类是 ASViewController 还是 ASDisplayNode 有很大的区别。这感觉上是显而易见的,但是有的区别是很微妙的,所有也需要特别注意。

ASDisplayNode

如果你使用的 node 组件类型于 UIView 的子控件,就必须注意下面几条准则以确保你充分发挥了这个框架的潜力, node 也能很好的显示。

-init

当使用 nodeBlock 的时候这个方法是在子线程进行的。但是,如何 -init 没有运行完,其他方法就无法运行,所以这个方法永远不要上锁。

最重要的是你的 init 方法一定要能在任何队列中调用。尤其是不要在初始化的时候初始化任何 UIKit 控件、点击 nodeview 或者 layer 或者添加任何手势。这些事情应该放在 -didLoad 中。

-didLoad

这个方法在概念上类似于 UIViewController-viewDidLoad 方法,它代表着后台的 view 已经被加载完成了。要确保它是在主线程中执行的,在这个方法中很适合处理 UIKit 的各种操作(比如添加手势,点击 view 或者 layer,初始化 UIKit 组件)。

-layout

在这个方法里调用 super 之后,布局规则对象会把所有的子节点都计算并且定位好,所以这个时间点是你手动进行布局所有子view的时机。或许更有用的是,有时候你想手动布局,但并不太容易创建一个布局规则对象,或者有时候你不想等所有子节点布局完毕,而只是很简单的手动设置frame,如果是这样的话,就在这个方法里写。

layoutSpecThatFits

这个方法就是用来建立布局规则对象,产生 node 大小以及所有子 node 大小的地方,你创建的布局规则对象一直持续到这个方法返回的时间点,经过了这个时间点后,它就不可变了。尤其重要要记住的一点事,千万不要缓存布局规则对象,当你以后需要他的时候,请重新创建。

ASViewController

ASViewControllerUIViewController 的子类,包含了管理 node 的特性。因此它的所有方法一定要在主线程中使用。

-init

这个方法只调用一次,是在 ASViewController 的生命周期的最开始的时候调用。在它初始化的过程中,不要使用 self.view 或者 self.node.view ,它会强制 view 被提前创建。这些事情应该在 viewDidLoad 中完成。

ASViewController 的初始化方法是 initWithNode: ,代码如下所示。一个 ASViewController 管理节点就像 UIViewController 管理 view 一样,但是初始化的过程有小小的差异。

1
2
3
4
5
6
7
8
9
10
11
12
13
- (instancetype)init {

_pagerNode = [[ASPagerNode alloc] init];
self = [super initWithNode:_pagerNode];

// setup any instance variables or properties here
if (self) {
_pagerNode.dataSource = self;
_pagerNode.delegate = self;
}

return self;
}

-loadView

建议不要使用这个方法,因为它相对于 viewDidLoad 来说没有明显的优势反而有很多不足的地方。但如果你不去设置 self.view 的属性就没什么问题。调用 [super loadView] 它就会执行 node.view

-viewDidLoad

它会在 ASViewController 的生命周期的最开始调用,仅次于 -loadView 。这是你使用节点的 view 最早的时机。在这个方法里适合放只执行一次并且要使用 view/layer 的代码,比如加手势。

布局的代码千万不要放在这个方法里,因为界面发生改变也不会再调用这个方法重新布局。

-viewWillLayoutSubviews

这个方法调用的时机和节点 -layout 方法调用的时机一样,它可以被执行很多次。只要它的节点被改变(比如旋转,分屏,显示键盘)或者继承()都会立即被调用。