mirror of
https://github.com/HackPlan/AsyncDisplayKit.git
synced 2026-04-24 03:45:58 +08:00
merged upstream
This commit is contained in:
@@ -1,21 +0,0 @@
|
||||
---
|
||||
title: ASCollectionNode
|
||||
layout: docs
|
||||
permalink: /docs/ascollectionnode.html
|
||||
next: astablenode.html
|
||||
---
|
||||
|
||||
ASCollectionNode can be used in place of any UICollectionView. The only requirements are that you replace your
|
||||
|
||||
<code>-cellForRowAtIndexPath:</code>
|
||||
|
||||
method with a
|
||||
|
||||
<code>-nodeForRowAtIndexPath:</code>
|
||||
|
||||
or
|
||||
|
||||
<code>-nodeBlockForRowAtIndexPath:</code>
|
||||
|
||||
Otherwise, a collection node has mostly the same delegate and dataSource methods that a collection view would and is compatible with most UICollectionViewLayouts.
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
---
|
||||
title: ASPagerNode
|
||||
layout: docs
|
||||
permalink: /docs/aspagernode.html
|
||||
next: ascollectionnode.html
|
||||
---
|
||||
|
||||
ASPagerNode is a specialized subclass of ASCollectionNode. Using it allows you to produce a page style UI similar to what you'd create with a UIPageViewController with UIKit. Luckily, the API is quite a bit simpler than UIPageViewController's.
|
||||
|
||||
The main dataSource methods are:
|
||||
|
||||
<code>- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode</code>
|
||||
|
||||
and
|
||||
|
||||
<code>- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index</code>
|
||||
|
||||
or
|
||||
|
||||
<code>- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index</code>
|
||||
|
||||
|
||||
These two methods, just as with ASCollectionNode and ASTableNode need to return either an ASCellNode or an block it can use to return one later.
|
||||
|
||||
One especially useful pattern is to return an ASCellNode that is initialized with an existing UIViewController or ASViewController.
|
||||
|
||||
```
|
||||
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
|
||||
{
|
||||
CGSize pagerNodeSize = pagerNode.bounds.size;
|
||||
NSArray *animals = self.animals[index];
|
||||
|
||||
ASCellNode *node = [[ASCellNode alloc] initWithViewControllerBlock:^{
|
||||
return [[AnimalTableNodeController alloc] initWithAnimals:animals];;
|
||||
} didLoadBlock:nil];
|
||||
|
||||
node.preferredFrameSize = pagerNodeSize;
|
||||
|
||||
return node;
|
||||
}
|
||||
```
|
||||
|
||||
In this example, you can see that the node is constructed using the `-initWithViewControllerBlock:` method. It is usually necessary to provide a cell created this way with a preferredFrameSize so that it can be laid out correctly.
|
||||
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
title: ASTableNode
|
||||
layout: docs
|
||||
permalink: /docs/astablenode.html
|
||||
next: display-node.html
|
||||
---
|
||||
|
||||
ASTableNode is equivalent to UIKit's UITableView.
|
||||
|
||||
<div class = "note">
|
||||
If you've used previous versions of ASDK, you'll notice that ASTableView has been removed in favor of ASTableNode. ASTableView (an actual UITableView subclass) is still in use as an internal property of ASTableNode but should no longer be used by itself.
|
||||
|
||||
That being said, you can still grab a reference to the underlying ASTableView if necessary by accessing the .view property of an ASTableNode.
|
||||
</div>
|
||||
|
||||
ASTableNode can be used in place of any UITableView. The only requirements are that you replace your
|
||||
|
||||
<code>-cellForRowAtIndexPath:</code>
|
||||
|
||||
method with a
|
||||
|
||||
<code>-nodeForRowAtIndexPath:</code>
|
||||
|
||||
or
|
||||
|
||||
<code>-nodeBlockForRowAtIndexPath:</code>
|
||||
|
||||
Otherwise, a table node has mostly the same delegate and dataSource methods that a table view would.
|
||||
|
||||
An important thing to notice is that ASTableNode does not provide a method called:
|
||||
|
||||
<code>-tableNode:HeightForRowAtIndexPath:</code>
|
||||
|
||||
This is because in ASDK, nodes are responsible for determining their height themselves which means you no longer have to write code to determine this detail at the view controller level.
|
||||
|
||||
71
_docs/batch-fetching-api.md
Normal file
71
_docs/batch-fetching-api.md
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: Batch Fetching API
|
||||
layout: docs
|
||||
permalink: /docs/batch-fetching-api.html
|
||||
next: image-modification-block.html
|
||||
---
|
||||
|
||||
AsyncDisplayKit's Batch Fetching API makes it easy for developers to add fetching of new data in chunks. In case the user scrolled to a specific range of a table or collection view the automatic batch fetching mechanism of ASDK kicks in.
|
||||
|
||||
You as a developer can define the point when the batch fetching mechanism should start via the `leadingScreensForBatching` property on an `ASTableView` or `ASCollectionView`. The default value for this property is 2.0.
|
||||
|
||||
To support batch fetching you have to implement two methods in your ASTableView or ASCollectionView delegate object:
|
||||
The first method you have to implement is for ASTableView delegate:
|
||||
|
||||
`- (BOOL)shouldBatchFetchForTableView:(ASTableView *)tableView`
|
||||
|
||||
or for ASCollectionView delegate:
|
||||
|
||||
`- (BOOL)shouldBatchFetchForCollectionView:(ASCollectionView *)collectionView`
|
||||
|
||||
In this method you have decide if the batch fetching mechanism should kick in if the user scrolled in batch fetching range or not. Usually this decision is based on if there is still data to fetch or not, based on e.g. previous API calls or some local dataset operations.
|
||||
|
||||
If you return NO from `- (BOOL)shouldBatchFetchForCollectionView:(ASCollectionView *)collectionView`, no new batch fetching process will happen, in case you return YES the batch fetching mechanism will start and the following method is called for your ASTableView delegate:
|
||||
|
||||
- (void)tableView:(ASTableView *)tableView willBeginBatchFetchWithContext:(ASBatchContext *)context;
|
||||
|
||||
or for ASCollectionView delegate:
|
||||
|
||||
- (void)collectionView:(ASCollectionView *)collectionView willBeginBatchFetchWithContext:(ASBatchContext *)context;
|
||||
|
||||
First of all, you have to be careful within this method as it's called on a background thread. If you have to do anything on the main thread, you are responsible for dispatching it to the main thread and proceed with work you have to do in process to finish the batch fetch.
|
||||
|
||||
Within `- (void)collectionView:(ASCollectionView *)collectionView willBeginBatchFetchWithContext:(ASBatchContext *)context;` you should do any necessary steps to fetch the next chunk of data e.g. from a local database, an API etc.
|
||||
|
||||
After you finished fetching the next chunk of data, it is very important to let ASDK know that you finished the process. To do that you have to call `completeBatchFetching:` on the `context` object that was passed in with a parameter value of YES. This assures that the whole batch fetching mechanism stays in sync and a next batch fetching cycle can happen. Only by passing YES will the context know to attempt another batch update when necessary. If you pass in NO nothing will happen.
|
||||
|
||||
Here you can see an example how a batch fetching cycle could look like:
|
||||
|
||||
```objective-c
|
||||
- (BOOL)shouldBatchFetchForTableView:(ASTableView *)tableView
|
||||
{
|
||||
// Decide if the batch fetching mechanism should kick in
|
||||
if (_stillDataToFetch) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)tableView:(ASTableView *)tableView willBeginBatchFetchWithContext:(ASBatchContext *)context
|
||||
{
|
||||
// Fetch data most of the time asynchronoulsy from an API or local database
|
||||
NSArray *data = ...;
|
||||
|
||||
// Insert data into table or collection view
|
||||
[self insertNewRowsInTableView:newPhotos];
|
||||
|
||||
// Decide if it's still necessary to trigger more batch fetches in the future
|
||||
_stillDataToFetch = ...;
|
||||
|
||||
// Properly finish the batch fetch
|
||||
[context completeBatchFetching:YES]
|
||||
}
|
||||
```
|
||||
|
||||
Check out the following sample apps to see the batch fetching API implemented within an app:
|
||||
<ul>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/Kittens">Kittens</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/CatDealsCollectionView">CatDealsCollectionView</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASCollectionView">ASCollectionView</a></li>
|
||||
</ul>
|
||||
96
_docs/containers-ascollectionnode.md
Executable file
96
_docs/containers-ascollectionnode.md
Executable file
@@ -0,0 +1,96 @@
|
||||
---
|
||||
title: ASCollectionNode
|
||||
layout: docs
|
||||
permalink: /docs/containers-ascollectionnode.html
|
||||
next: 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
|
||||
|
||||
`collectionView:cellForItemAtIndexPath:`
|
||||
|
||||
with your choice of **_one_** of the following methods
|
||||
|
||||
`- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath`
|
||||
|
||||
or
|
||||
|
||||
`- (ASCellNodeBlock)collectionView:(ASCollectionView *)collectionView nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath` **_(recommended)_**
|
||||
|
||||
<div class = "note">
|
||||
Note that these are the same methods as the `ASTableNode`! Please read the previous <a href = "containers-astablenode.html">`ASTableNode`</a> section as most of the details here are identical and so we will gloss over them quickly.
|
||||
</div>
|
||||
|
||||
As noted in the previous section
|
||||
<ul>
|
||||
<li>both of these ASCollectionView methods should not implement reuse (they will be called once per row)</li>
|
||||
<li>`collectionView:nodeBlockForRowAtIndexPath:` is preferred to `collectionView:nodeForItemAtIndexPath:` for its concurrent processing</li>
|
||||
<li>it is very important that node blocks be thread-safe</li>
|
||||
<li>ASCellNodes are used by ASTableNode, ASCollectionNod and ASPagerNode</li>
|
||||
</ul>
|
||||
|
||||
##Replace UICollectionViewController with ASViewController##
|
||||
|
||||
AsyncDisplayKit does not offer an equivalent to UICollectionViewController. Instead, use an ASViewController initialized with an ASCollectionNode.
|
||||
|
||||
Consider, the ASViewController subclass - LocationCollectionNodeController - from the <a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram sample app</a> that uses a collection node as its managed node.
|
||||
|
||||
An `ASCollectionNode` is assigned to be managed by an `ASViewController` in its `initWithNode:` designated initializer method.
|
||||
|
||||
```objective-c
|
||||
- (instancetype)initWithCoordinates:(CLLocationCoordinate2D)coordinates
|
||||
{
|
||||
_flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||||
_collectionNode = [[ASCollectionNode alloc] initWithCollectionViewLayout:_flowLayout];
|
||||
|
||||
self = [super initWithNode:_collectionNode];
|
||||
if (self) {
|
||||
_flowLayout.minimumInteritemSpacing = 1;
|
||||
_flowLayout.minimumLineSpacing = 1;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
```
|
||||
|
||||
##Accessing the ASCollectionView##
|
||||
If you've used previous versions of ASDK, you'll notice that `ASCollectionView` has been removed in favor of `ASCollectionNode`.
|
||||
|
||||
<div class = "note">
|
||||
`ASCollectionView` (an actual UICollectionView subclass) is still used as an internal property of `ASCollectionNode`. While it should not be created directly, it can still be used directly by accessing the .view property of an `ASCollectionNode`.
|
||||
</div>
|
||||
|
||||
**Do not forget that anything that accesses a view using AsyncDisplayKit's node containers or nodes should be done in viewDidLoad or didLoad, respectively.**
|
||||
|
||||
The LocationCollectionNodeController above accesses the ASCollectionView directly in viewDidLoad
|
||||
|
||||
```objective-c
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
_collectionNode.view.asyncDelegate = self;
|
||||
_collectionNode.view.asyncDataSource = self;
|
||||
_collectionNode.view.allowsSelection = NO;
|
||||
_collectionNode.view.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
```
|
||||
|
||||
##Table Row Height##
|
||||
|
||||
As discussed in the previous <a href = "containers-astablenode.html">`ASTableNode`</a> section, ASCollectionNodes and ASTableNodes do not need to keep track of the height of their ASCellNodes.
|
||||
|
||||
***constrainedSizeForNode (also in table, but more important for collection)
|
||||
- check that (0,0) min and (infinity, infinity) max
|
||||
- example sample photo grid
|
||||
- popover, rotated -> how to get size constraint (USE constrainedSizeForNode to do simple divide by 3 width thing)
|
||||
- document itemSize (check what happens in ASDKgram)
|
||||
|
||||
##Sample Apps with ASCollectionNodes##
|
||||
<ul>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/CatDealsCollectionView">CatDealsCollectionView</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASCollectionView">ASCollectionView</a></li>
|
||||
</ul>
|
||||
78
_docs/containers-aspagernode.md
Executable file
78
_docs/containers-aspagernode.md
Executable file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
title: ASPagerNode
|
||||
layout: docs
|
||||
permalink: /docs/containers-aspagernode.html
|
||||
next: display-node.html
|
||||
---
|
||||
|
||||
`ASPagerNode` is a subclass of `ASCollectionNode`.
|
||||
|
||||
Using it allows you to produce a page style UI similar to what you'd create with UIKit's `UIPageViewController`. ASPager node currently supports staying on the correct page during rotation. It does _not_ currently support circular scrolling.
|
||||
|
||||
The main dataSource methods are:
|
||||
|
||||
`- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode`
|
||||
|
||||
and
|
||||
|
||||
`- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index`
|
||||
|
||||
or
|
||||
|
||||
`- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index` **_(recommended)_**
|
||||
|
||||
These two methods, just as with `ASCollectionNode` and `ASTableNode` need to return either an `ASCellNode` or an `ASCellNodeBlock` - a block that creates a `ASCellNode` which can be run on a background thread.
|
||||
|
||||
Note that both of these methods should not implement reuse (they will be called once per row). Unlike UIKit, these methods are not called when the row is just about to display.
|
||||
|
||||
While `pagerNode:nodeAtIndex:` will be called on the main thread, `pagerNode:nodeBlockAtIndex:` is preferred because it concurrently allocates cell nodes, meaning that all of the `init:` methods for all of your subnodes are run in the background. **It is very important that node blocks be thread-safe** as they can be called on the main thread or a background queue.
|
||||
|
||||
##Node Block Thread Safety Warning##
|
||||
|
||||
It is imperative that the data model be accessed outside of the node block. This means that it is highly unlikely that you should need to use the index inside of the block.
|
||||
|
||||
In the example below, you can see how the index is used to access the photo model before creating the node block.
|
||||
|
||||
```objective-c
|
||||
- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index
|
||||
{
|
||||
PhotoModel *photoModel = [_photoFeed objectAtIndex:index];
|
||||
|
||||
// this part can be executed on a background thread - it is important to make sure it is thread safe!
|
||||
ASCellNode *(^ASCellNodeBlock)() = ^ASCellNode *() {
|
||||
PhotoCellNode *cellNode = [[PhotoCellNode alloc] initWithPhotoObject:photoModel];
|
||||
return cellNode;
|
||||
};
|
||||
|
||||
return ASCellNodeBlock;
|
||||
}
|
||||
```
|
||||
|
||||
##Use ASViewControllers For Optimal Performance##
|
||||
|
||||
One especially useful pattern is to return an ASCellNode that is initialized with an existing UIViewController or ASViewController. For optimal performance, use an ASViewController.
|
||||
|
||||
```objective-c
|
||||
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
|
||||
{
|
||||
CGSize pagerNodeSize = pagerNode.bounds.size;
|
||||
NSArray *animals = self.animals[index];
|
||||
|
||||
ASCellNode *node = [[ASCellNode alloc] initWithViewControllerBlock:^{
|
||||
return [[AnimalTableNodeController alloc] initWithAnimals:animals];;
|
||||
} didLoadBlock:nil];
|
||||
|
||||
node.preferredFrameSize = pagerNodeSize;
|
||||
|
||||
return node;
|
||||
}
|
||||
```
|
||||
In this example, you can see that the node is constructed using the `-initWithViewControllerBlock:` method. It is usually necessary to provide a cell created this way with a preferredFrameSize so that it can be laid out correctly.
|
||||
|
||||
##Sample Apps##
|
||||
|
||||
Check out the following sample apps to see an ASPagerNode implemented within an app:
|
||||
<ul>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/PagerNode">PagerNode</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/VerticalWithinHorizontalScrolling">VerticalWithinHorizontalScrolling</a></li>
|
||||
</ul>
|
||||
119
_docs/containers-astablenode.md
Executable file
119
_docs/containers-astablenode.md
Executable file
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: ASTableNode
|
||||
layout: docs
|
||||
permalink: /docs/containers-astablenode.html
|
||||
next: containers-ascollectionnode.html
|
||||
---
|
||||
|
||||
`ASTableNode` is equivalent to UIKit's `UITableView` and can be used in place of any UITableView.
|
||||
|
||||
ASTableNode replaces UITableView's required method
|
||||
|
||||
`tableView:cellForRowAtIndexPath:`
|
||||
|
||||
with your choice of **_one_** of the following methods
|
||||
|
||||
`- (ASCellNode *)tableView:(ASTableView *)tableView nodeForRowAtIndexPath:(NSIndexPath *)indexPath`
|
||||
|
||||
or
|
||||
|
||||
`- (ASCellNodeBlock)tableView:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath` **_(recommended)_**
|
||||
|
||||
These two methods, need to return either an <a href = "cell-node.html">`ASCellNode`</a> or an `ASCellNodeBlock`. An ASCellNodeBlock is a block that creates a ASCellNode which can be run on a background thread. Note that ASCellNodes are used by ASTableNode, ASCollectionNod and ASPagerNode.
|
||||
|
||||
Note that both of these methods should not implement reuse (they will be called once per row). However, unlike UITableView, these methods are not called when the row is just about to display.
|
||||
|
||||
####Node Blocks are Best####
|
||||
|
||||
While `tableView:nodeForRowAtIndexPath:` will be called on the main thread, `tableView:nodeBlockForRowAtIndexPath:` is preferred because it concurrently allocates cell nodes. This means that all of the init: methods for all of your subnodes are run in the background.
|
||||
|
||||
##Replace UITableViewController with ASViewController##
|
||||
|
||||
AsyncDisplayKit does not offer an equivalent to UITableViewController. Instead, use an ASViewController initialized with an ASTableNode.
|
||||
|
||||
Consider, again, the ASViewController subclass - PhotoFeedNodeController - from the <a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram sample app</a> that uses a table node as its managed node.
|
||||
|
||||
An `ASTableNode` is assigned to be managed by an `ASViewController` in its `initWithNode:` designated initializer method.
|
||||
|
||||
```objective-c
|
||||
- (instancetype)init
|
||||
{
|
||||
_tableNode = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];
|
||||
self = [super initWithNode:_tableNode];
|
||||
|
||||
if (self) {
|
||||
_tableNode.dataSource = self;
|
||||
_tableNode.delegate = self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
```
|
||||
|
||||
##Node Block Thread Safety Warning##
|
||||
|
||||
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 `tableView:nodeBlockForRowAtIndexPath:` method from the `PhotoFeedNodeController.m` file in the <a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram sample app</a>.
|
||||
|
||||
In the example below, you can see how the index is used to access the photo model before creating the node block.
|
||||
|
||||
```objective-c
|
||||
- (ASCellNodeBlock)tableView:(ASTableView *)tableView 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 *(^ASCellNodeBlock)() = ^ASCellNode *() {
|
||||
PhotoCellNode *cellNode = [[PhotoCellNode alloc] initWithPhotoObject:photoModel];
|
||||
cellNode.delegate = self;
|
||||
return cellNode;
|
||||
};
|
||||
|
||||
return ASCellNodeBlock;
|
||||
}
|
||||
```
|
||||
|
||||
##Accessing the ASTableView##
|
||||
If you've used previous versions of ASDK, you'll notice that `ASTableView` has been removed in favor of `ASTableNode`.
|
||||
|
||||
<div class = "note">
|
||||
`ASTableView` (an actual UITableView subclass) is still used as an internal property of `ASTableNode`. While it should not be created directly, it can still be used directly by accessing the .view property of an `ASTableNode`.
|
||||
</div>
|
||||
|
||||
**Do not forget that anything that accesses a view using AsyncDisplayKit's node containers or nodes should be done in viewDidLoad or didLoad, respectively.**
|
||||
|
||||
For example, you may want to set a table's separator style property. This can be done by accessing the table node's view in the `viewDidLoad:` method as seen in the example below.
|
||||
|
||||
```objective-c
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
_tableNode.view.allowsSelection = NO;
|
||||
_tableNode.view.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
_tableNode.view.leadingScreensForBatching = AUTO_TAIL_LOADING_NUM_SCREENFULS; // overriding default of 2.0
|
||||
}
|
||||
```
|
||||
|
||||
##Table Row Height##
|
||||
|
||||
An important thing to notice is that `ASTableNode` does not provide an equivalent to `UITableView`'s
|
||||
|
||||
`tableView:heightForRowAtIndexPath:`
|
||||
|
||||
This is because in AsyncDisplayKit, nodes are responsible for determining their height themselves which means you no longer have to write code to determine this detail at the view controller level.
|
||||
|
||||
A node defines its height by way of its layoutSpec returned in the `- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize` method. All nodes given a constrained size are able to calculate their desired size. **Note that nodes that don't have an inherent size, such as an image or map) must set their `.preferredFrameSize` property.**
|
||||
|
||||
**By default, the size range provided to the cell is the width of the table and zero height (min) and maximum is width of table and infinite height (max).**
|
||||
|
||||
This is the magic of the `ASTableView`. From the level of the ASCellNode, the cell can very easily control it’s height and the tableNode will automatically adjust accordingly. For an example of this in action, see how the <a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram sample app</a> inserts comments below comments at a later time, increasing the height magically!
|
||||
|
||||
If you call `-setNeedsLayout` on an `ASCellNode`, it will automatically be perform its layout measurement again and if its overall desired size has changed, the table or collection will be informed and update. This is different from UIKit where normally you would have to call reload row / item. This saves tons of code, check out the <a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram sample app</a> to see side by side implementations of an UITableView and ASTableNode implemented social media feed.
|
||||
|
||||
##Sample Apps with ASTableNodes##
|
||||
<ul>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram</a></li>
|
||||
<li><a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/Kittens">Kittens</a></li>
|
||||
</ul>
|
||||
40
_docs/containers-asviewcontroller.md
Executable file
40
_docs/containers-asviewcontroller.md
Executable file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
title: ASViewController
|
||||
layout: docs
|
||||
permalink: /docs/containers-asviewcontroller.html
|
||||
next: containers-astablenode.html
|
||||
---
|
||||
|
||||
`ASViewController` is a subclass of `UIViewController` that adds several useful features for hosting `ASDisplayNode` hierarchies.
|
||||
|
||||
An `ASViewController` can be used in place of any `UIViewController` - including within a `UINavigationController`, `UITabBarController` and `UISpitViewController` or as a modal view controller.
|
||||
|
||||
One of the main benefits to using an `ASViewController` is to save memory. An `ASViewController` that goes off screen will automatically reduce the size of the fetch data and display ranges of any of its children. This is key for memory management in large applications.
|
||||
|
||||
More features will be added over time, so it is a good idea to base your view controllers off of this class.
|
||||
|
||||
A `UIViewController` provides a view of its own. An `ASViewController` is assigned a node to manage in its designated initializer `initWithNode:`.
|
||||
|
||||
Consider the following `ASViewController` subclass `PhotoFeedNodeController` from the <a href="https://github.com/facebook/AsyncDisplayKit/tree/master/examples/ASDKgram">ASDKgram sample app</a> that would like to use a table node as its managed node.
|
||||
|
||||
This table node is assigned to the `ASViewController` in its `initWithNode:` designated initializer method.
|
||||
|
||||
```objective-c
|
||||
- (instancetype)init
|
||||
{
|
||||
_tableNode = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];
|
||||
self = [super initWithNode:_tableNode];
|
||||
|
||||
if (self) {
|
||||
_tableNode.dataSource = self;
|
||||
_tableNode.delegate = self;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
```
|
||||
|
||||
<div class = "note">
|
||||
If your app already has a complex view controller hierarchy, it is perfectly fine to have all of them subclass `ASViewController`. That is to say, even if you don't use `ASViewController`'s designated initializer `initiWithNode:`, and only use the `ASViewController` in the manner of a traditional `UIVieWController`, this will give you the additional node support if you choose to adopt it in different areas your application.
|
||||
</div>
|
||||
|
||||
24
_docs/containers-overview.md
Normal file
24
_docs/containers-overview.md
Normal file
@@ -0,0 +1,24 @@
|
||||
---
|
||||
title: Containers Overview
|
||||
layout: docs
|
||||
permalink: /docs/containers-overview.html
|
||||
next: containers-asviewcontroller.html
|
||||
---
|
||||
|
||||
##Use Nodes in Node Containers##
|
||||
It is highly recommended that you use AsyncDisplayKit's nodes within a node container. AsyncDisplayKit offers the following node containers
|
||||
|
||||
- `ASViewController` in place of UIKit's `UIViewController`
|
||||
- `ASCollectioNode` in place of UIKit's `UICollectionView`
|
||||
- `ASPagerNode` in place of UIKit's `UIPageViewController`
|
||||
- `ASTableNode` in place of UIKit's `UITableView`
|
||||
|
||||
Example code and specific sample projects are highlighted in the documentation for each node container.
|
||||
|
||||
For a detailed description on porting an existing UIKit app to AsyncDisplayKit, read the <a href = "porting-guide.html">porting guide</a>.
|
||||
|
||||
####What do I Gain by Using a Node Container?####
|
||||
|
||||
A node container automatically manages the <a href = "intelligent-preloading.html">intelligent preloading</a> of its nodes. This means that all of the node's layout measurement, data fetching, decoding and rendering will be done asynchronously. Among other conveniences, this is why it is reccomended to use nodes within a container node.
|
||||
|
||||
Note that while it _is_ possible to use nodes directly (without an AsyncDisplayKit node container), unless you add additional calls, they will only start displaying once they come onscreen (as UIKit does). This can lead to performance degredation and flashing of content.
|
||||
@@ -5,4 +5,7 @@ permalink: /docs/control-node.html
|
||||
next: button-node.html
|
||||
---
|
||||
|
||||
<div>😑 This page is coming soon...</div>
|
||||
<div>😑 This page is coming soon...</div>
|
||||
|
||||
####Tappable Area Visualization####
|
||||
With just one line of code, you can easily visualize the tappable areas of all ASControlNodes in your app using the <a href = "debug-tool-hit-test-slop.html">hit test slop debug tool</a>.
|
||||
|
||||
@@ -5,14 +5,26 @@ permalink: /docs/debug-tool-hit-test-slop.html
|
||||
next: debug-tool-ASRangeController.html
|
||||
---
|
||||
|
||||
## Visualize tappable areas on ASControlNodes
|
||||
### Description
|
||||
This debug feature adds a semi-transparent neon green highlight overlay on any ASControlNodes that have a `target:action:` pair added. The tappable range is defined as the ASControlNode’s frame + its hitTestSlop (UIEdgeInsets used by the ASControlNode to extend it’s tappable range).
|
||||
##Visualize ASControlNode Tappable Areas##
|
||||
This debug feature adds a semi-transparent highlight overlay on any ASControlNodes containing a `target:action:` pair or gesture recognizer. The tappable range is defined as the ASControlNode’s frame + its `.hitTestSlop` `UIEdgeInsets`. Hit test slop is a unique feature of `ASControlNode` that allows it to extend its tappable range.
|
||||
|
||||
**This debug feature is useful for quickly visualizing an ASControlNode's tappable range.** In the screenshot below, you can quickly see 3 things: (1) The tappable area for the avatar image overlaps the username’s tappable area. In this case, the user avatar image is on top in the view hierarchy and is capturing some touches that should go to the username. (2) It would probably make sense to expand the hitTestSlop for the username to allow the user to more easily hit it. (3) I’ve accidentally set the hitTestSlop’s UIEdgeInsets to be positive instead of negative for the photo likes count label. It’s going to be hard for a user to tap the smaller target.
|
||||
In the screenshot below, you can quickly see that
|
||||
<ul>
|
||||
<li>The tappable area for the avatar image overlaps the username’s tappable area. In this case, the user avatar image is on top in the view hierarchy and is capturing some touches that should go to the username.</li>
|
||||
<li>It would probably make sense to expand the `.hitTestSlop` for the username to allow the user to more easily hit it.</li>
|
||||
<li>I’ve accidentally set the hitTestSlop’s UIEdgeInsets to be positive instead of negative for the photo likes count label. It’s going to be hard for a user to tap the smaller target.</li>
|
||||
</ul>
|
||||
|
||||

|
||||
### Usage
|
||||
In your AppDelegate, (1) import `AsyncDisplayKit+Debug.h` and (2) at the top of `didFinishLaunchingWithOptions:` enable this feature by adding` [ASControlNode setEnableHitTestDebug:YES];` Make sure to call this method before initializing any ASControlNodes (including ASButtonNodes, ASImageNodes, and ASTextNodes).
|
||||
### Limitations
|
||||
This only works for ASControlNodes’s with `addTarget:action:` pairs added. **It will not work with gesture recognizers.**
|
||||
|
||||
##Restrictions##
|
||||
|
||||
A _green_ border on the edge(s) of the highlight overlay indicates that that edge of the tapable area is restricted by one of it's superview's tapable areas. An _orange_ border on the edge(s) of the highlight overlay indicates that that edge of the tapable area is clipped by .clipsToBounds of a parent in its hierarchy.
|
||||
|
||||
##Usage##
|
||||
In your `AppDelegate.m` file,
|
||||
<ul>
|
||||
<li>import `AsyncDisplayKit+Debug.h`</li>
|
||||
<li>add `[ASControlNode setEnableHitTestDebug:YES]` at the top of your `didFinishLaunchingWithOptions:` method</li>
|
||||
</ul>
|
||||
Make sure to call this method before initializing any ASControlNodes - including ASButtonNodes, ASImageNodes, and ASTextNodes.
|
||||
|
||||
@@ -5,21 +5,33 @@ permalink: /docs/debug-tool-pixel-scaling.html
|
||||
next: debug-tool-hit-test-slop.html
|
||||
---
|
||||
|
||||
## Visualize ASImageNode.image’s pixel scaling
|
||||
### Description
|
||||
This debug feature adds a red text label overlay on the bottom right hand corner of an ASImageNode if (and only if) the image’s size in pixels does not match it’s bounds size in pixels, e.g.
|
||||
##Visualize ASImageNode.image’s pixel scaling##
|
||||
This debug feature adds a red text overlay on the bottom right hand corner of an ASImageNode if (and only if) the image’s size in pixels does not match it’s bounds size in pixels, e.g.
|
||||
|
||||
`imageSizeInPixels = image.size * image.scale`
|
||||
`boundsSizeInPixels = bounds.size * contentsScale`
|
||||
`scaleFactor = imageSizeInPixels / boundsSizeInPixels`
|
||||
```objective-c
|
||||
imageSizeInPixels = image.size * image.scale
|
||||
boundsSizeInPixels = bounds.size * contentsScale
|
||||
scaleFactor = imageSizeInPixels / boundsSizeInPixels
|
||||
|
||||
`if (scaleFactor != 1.0) {`
|
||||
`NSString *scaleString = [NSString stringWithFormat:@"%.2fx", scaleFactor];`
|
||||
`_debugLabelNode.hidden = NO;`
|
||||
`}`
|
||||
if (scaleFactor != 1.0) {
|
||||
NSString *scaleString = [NSString stringWithFormat:@"%.2fx", scaleFactor];
|
||||
_debugLabelNode.hidden = NO;
|
||||
}
|
||||
```
|
||||
|
||||
This debug feature is useful for **quickly determining if you are (1) downloading and rendering excessive amounts of image data or (2) upscaling a low quality image**. In the screenshot below, you can quickly see that the avatar image is unnecessarily large for it’s bounds size and that the center picture is more optimized, but not perfectly so. If you are using an external data source (such as the 500px API used in the example), it's likely that you won’t be able to get the scaleFactor to exactly 1.0. However, if you control your own endpoint, optimize your API / app to return a correctly sized image!
|
||||
**This debug feature is useful for quickly determining if you are**
|
||||
<ul>
|
||||
<li><strong>downloading and rendering excessive amounts of image data</li>
|
||||
<li>upscaling a low quality image</strong></li>
|
||||
</ul>
|
||||
|
||||
In the screenshot below of an app with this debug feature enabled, you can see that the avatar image is unnecessarily large (9x too large) for it’s bounds size and that the center picture is more optimized, but not perfectly so. If you control your own endpoint, optimize your API / app to return an optimally sized image.
|
||||
|
||||

|
||||
### Usage
|
||||
In your AppDelegate, (1) import `AsyncDisplayKit+Debug.h` and (2) at the top of `didFinishLaunchingWithOptions:` enable this feature by adding `[ASImageNode setShouldShowImageScalingOverlay:YES];` Make sure to call this method before initializing any ASImageNodes.
|
||||
##Usage##
|
||||
In your `AppDelegate.m` file,
|
||||
<ul>
|
||||
<li>import `AsyncDisplayKit+Debug.h`</li>
|
||||
<li>add `[ASImageNode setShouldShowImageScalingOverlay:YES]` at the top of your `didFinishLaunchingWithOptions:` method</li>
|
||||
</ul>
|
||||
Make sure to call this method before initializing any ASImageNodes.
|
||||
|
||||
@@ -5,4 +5,7 @@ permalink: /docs/image-node.html
|
||||
next: network-image-node.html
|
||||
---
|
||||
|
||||
<div>😑 This page is coming soon...</div>
|
||||
<div>😑 This page is coming soon...</div>
|
||||
|
||||
####ASImageNode Performance Tip####
|
||||
With just one line of code, you can easily check that your app isn't downloading and rendering excessive amounts of image data or upscaling a low quality image using the <a href = "debug-tool-pixel-scaling.html">pixel scaling debug tool</a>.
|
||||
|
||||
Reference in New Issue
Block a user