title | layout | permalink | prevPage | nextPage |
---|---|---|---|---|
ASCollectionNode |
docs |
/docs/containers-ascollectionnode.html |
containers-astablenode.html |
containers-aspagernode.html |
ASCollectionNode
is equivalent to UIKit's UICollectionView
and can be used in place of any UICollectionView
.
ASCollectionNode
replaces UICollectionView
's required method
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
with your choice of one of the following methods
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath
override func collectionNode(_ collectionNode: ASCollectionNode, nodeForItemAt indexPath: IndexPath) -> ASCellNode
or
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath
override func collectionNode(_ collectionNode: ASCollectionNode, nodeBlockForItemAt indexPath: IndexPath) -> ASCellNodeBlock
It is recommended that you use the node block version of the method so that your collection node will be able to prepare and display all of its cells concurrently.
As noted in the previous section:
- ASCollectionNodes do not utilize cell reuse.
- Using the "nodeBlock" method is preferred.
- It is very important that the returned node blocks are thread-safe.
- ASCellNodes can be used by ASTableNode, ASCollectionNode and ASPagerNode.
It is very important that node blocks be thread-safe. One aspect of that is ensuring that the data model is accessed outside of the node block. Therefore, it is unlikely that you should need to use the index inside of the block.
Consider the following -collectionNode:nodeBlockForItemAtIndexPath:
method.
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(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;
}
func collectionNode(_ collectionNode: ASCollectionNode, nodeBlockForItemAt indexPath: IndexPath) -> ASCellNodeBlock {
guard photoFeed.count > indexPath.row else { return { ASCellNode() } }
let photoModel = photoFeed[indexPath.row]
// this may be executed on a background thread - it is important to make sure it is thread safe
let cellNodeBlock = { () -> ASCellNode in
let cellNode = PhotoCellNode(photo: photoModel)
cellNode.delegate = self
return cellNode
}
return cellNodeBlock
}
In the example above, you can see how the index is used to access the photo model before creating the node block.
Texture does not offer an equivalent to UICollectionViewController. Instead, you can use the flexibility of ASDKViewController to recreate any type of UI...ViewController.
Consider, the following ASDKViewController subclass.
An ASCollectionNode is assigned to be managed by an ASDKViewController
in its -initWithNode:
designated initializer method, thus making it a sort of ASCollectionNodeController.
- (instancetype)init
{
_flowLayout = [[UICollectionViewFlowLayout alloc] init];
_collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:_flowLayout];
self = [super initWithNode:_collectionNode];
if (self) {
_flowLayout.minimumInteritemSpacing = 1;
_flowLayout.minimumLineSpacing = 1;
}
return self;
}
init() {
flowLayout = UICollectionViewFlowLayout()
collectionNode = ASCollectionNode(collectionViewLayout: flowLayout)
super.init(node: collectionNode)
flowLayout.minimumInteritemSpacing = 1
flowLayout.minimumLineSpacing = 1
}
This works just as well with any node including as an ASTableNode, ASPagerNode, etc.
If you've used previous versions of Texture, you'll notice that ASCollectionView
has been removed in favor of ASCollectionNode
.
Don't forget that a node's `view` or `layer` property should only be accessed after viewDidLoad or didLoad, respectively, have been called.
The LocationCollectionNodeController
above accesses the ASCollectionView
directly in -viewDidLoad
.
- (void)viewDidLoad
{
[super viewDidLoad];
_collectionNode.delegate = self;
_collectionNode.dataSource = self;
_collectionNode.view.allowsSelection = NO;
_collectionNode.view.backgroundColor = [UIColor whiteColor];
}
override func viewDidLoad() {
super.viewDidLoad()
collectionNode.delegate = self
collectionNode.dataSource = self
collectionNode.view.allowsSelection = false
collectionNode.view.backgroundColor = .white
}
As discussed in the previous section, ASCollectionNode
and ASTableNode
do not need to keep track of the height of their ASCellNode
s.
Right now, cells will grow to fit their constrained size and will be laid out by whatever UICollectionViewLayout
you provide.
You can also constrain cells used in a collection node using ASCollectionNode
's -constrainedSizeForItemAtIndexPath:
.
The most detailed example of laying out the cells of an ASCollectionNode
is the CustomCollectionView app. It includes a Pinterest style cell layout using an ASCollectionNode
and a custom UICollectionViewLayout
.
ASCollectionNode
supports using UICollectionViewCells
alongside native ASCellNodes
.
Note that these UIKit cells will not have the performance benefits of ASCellNodes
(like preloading, async layout, and async drawing), even when mixed within the same ASCollectionNode
.
However, this interoperability allows developers the flexibility to test out the framework without needing to convert all of their cells at once. Read more here.