Node Containers
ASViewController
ASViewController
是UIViewController
的子类,添加了一些有用的功能来承载ASDisplayNode
层次结构
可以使用ASViewController
代替任何UIViewControlller
使用ASViewController
的好处:
- 保存内存。
- ASVisibility
使用
UIViewController
提供了自己的View。ASViewController
在初始化时 通过initWithNode
分配了要管理的节点
//例如 修改视图控制器的视图的根node 为 table node
- (instancetype)init
{
_tableNode = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];
self = [super initWithNode:_tableNode];
if (self) {
_tableNode.dataSource = self;
_tableNode.delegate = self;
}
return self;
}
ASTableNode
相当于UITableView
并且可以用来代替任何UITableView
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
//替换方法
- (ASCellNode *)tableNode:(ASTableNode *)tableNode nodeForRowAtIndexPath:(NSIndexPath *)indexPath
//或者
- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath
建议使用 nodeblock版本,以便table node可以同时准备和display。这意味着所有的
subnode
初始化方法都会在后台运行,请确保线程安全。
ASCellNodeBlock
是创建ASCellNode
的block,能够在后台线程运行。
注意
ASCellNodes
被ASTableNode、ASCollectionNode、ASPagerNode
使用这些方法均不需要重用机制(只会执行一次,与UIKIt不同,当行要显示时不会调用这些方法)
node block的线程安全
node blocks必须是线程安全的。一方面是确保在node block外访问数据模型。因此,不太需要会在block内部访问indexPath
- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath
{
PhotoModel *photoModel = [_photoFeed objectAtIndex:indexPath.row];
// this may be executed on a background thread - it is important to make sure it is thread safe
ASCellNode *(^cellNodeBlock)() = ^ASCellNode *() {
PhotoCellNode *cellNode = [[PhotoCellNode alloc] initWithPhoto:photoModel];
cellNode.delegate = self;
return cellNode;
};
return cellNodeBlock;
}
ASTableView的访问
ASTableView
是UITalbeView
的子类,在ASTalbeNode
内部进行使用,可以在viewDidLoad
或didLoad
方法找中通过.view
属性访问节点的view
或者layer
属性
例如,可以再ViewDidLoad
方法中 访问呢表节点的视图完成对表格的分隔符样式设置
- (void)viewDidLoad
{
[super viewDidLoad];
_tableNode.view.allowsSelection = NO;
_tableNode.view.separatorStyle = UITableViewCellSeparatorStyleNone;
_tableNode.view.leadingScreensForBatching = 3.0; // default is 2.0
}
行高
需要注意的是: ASTableNode不提供和UITableView
的tableView:heightForRowAtIndexPath
等效功能
这是因为node 会根据提供的约束确定其自身的高度,因此不再需要编写代码在视图控制器中确定此信息
node通过layoutSpecThatFits
方法 返回的layoutSpec
定义其高度。所有给定了限制size的node都可以计算其目标size
默认情况,ASTableNode
给其cell提供的大小范围约束,其中最小宽度为tablenode的宽度,最小高度为0.最大宽度为tablenode的宽度,最大高度为FLT_MAX
,就是说table的cell宽度是固定的为整个table的宽度,但是其高度时灵活的,可以自动调整大小
如果在ASCellNode
上调用-setNeddsLayout
将自动执行一遍布局,如果总体所需大小已经更改,通知table 将会进行更新
注意
这些规则和UIKit不同,在UIKit中必须调用reload row/item。这样就节省了大量代码
ASCollectionNode
ASCollectionNode 等效于 UICollectionView 可以在任何情况下替代UICollectionView
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
//替换为
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath
//或
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
推荐使用node block
cell 大小和布局
可以使用ASCollectionNode
的-constrainedSizeForItemAtIndexPath:
约束colletion node中使用的cell
UICollectionViewCell的互通性
ASCollectionNode
支持UICollectionViewCells
和ASCellNodes
一起使用
注意:即使混合在统一ASCollectionNode
中,这些UIKit
组件也不会有ASCellNode
的性能优势
ASPageNode
ASPageNode
是ASCollectionView
的子类,只是内部采用了特殊的UIColelctionViewLayout
ASPageNode
可以创建出类似UIPageViewController
创建的页面UI。支持在轮换期间停留在正确的页面。不支持循环滚动
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode
//和
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
//或者
- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index`
使用ASViewController来获得最佳性能
一种特别有用的模式就是 返回 使用现有UIViewController
或者ASViewController
初始化的ASCellNode。当然,为了获得最佳性能请使用ASViewController
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
{
NSArray *animals = self.animals[index];
ASCellNode *node = [[ASCellNode alloc] initWithViewControllerBlock:^{
return [[AnimalTableNodeController alloc] initWithAnimals:animals];;
} didLoadBlock:nil];
node.style.preferredSize = pagerNode.bounds.size;
return node;
}
在这个例子中,该节点使用initWithViewControllerBlock:
方法构造。通常时必须采用这种方法,以便执行正确的布局