mirror of
https://github.com/HackPlan/AsyncDisplayKit.git
synced 2026-05-18 01:02:13 +08:00
Merge pull request #127 from facebook/manual-display
Add -[ASDisplayNode display].
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -22,3 +22,5 @@ docs/htdocs
|
||||
docs/.sass-cache
|
||||
|
||||
*.swp
|
||||
|
||||
*.lock
|
||||
|
||||
@@ -294,6 +294,19 @@
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL shouldRasterizeDescendants;
|
||||
|
||||
/**
|
||||
* @abstract Calls -setNeedsDisplay and -displayIfNeeded on the node's backing store.
|
||||
*
|
||||
* @note This method must be called on the main thread but there are plans to allow this on any thread.
|
||||
*/
|
||||
- (void)display;
|
||||
|
||||
/**
|
||||
* @abstract Call -display on the node and recursively on all subnodes, forcing the entire node hierarchy to be
|
||||
* displayed.
|
||||
*/
|
||||
- (void)recursivelyDisplay;
|
||||
|
||||
/**
|
||||
* @abstract Display the node's view/layer immediately on the current thread, bypassing the background thread rendering.
|
||||
*/
|
||||
|
||||
@@ -437,6 +437,33 @@ void ASDisplayNodePerformBlockOnMainThread(void (^block)())
|
||||
_contentsScaleForDisplay = contentsScaleForDisplay;
|
||||
}
|
||||
|
||||
- (void)display
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert(self.nodeLoaded, @"backing store must be loaded before calling -display");
|
||||
|
||||
// rendering a backing store requires a node be laid out
|
||||
[self __layout];
|
||||
|
||||
CALayer *layer = [self isLayerBacked] ? self.layer : self.view.layer;
|
||||
|
||||
if (layer.contents) {
|
||||
return;
|
||||
}
|
||||
|
||||
[layer setNeedsDisplay];
|
||||
[layer displayIfNeeded];
|
||||
}
|
||||
|
||||
- (void)recursivelyDisplay
|
||||
{
|
||||
for (ASDisplayNode *node in self.subnodes) {
|
||||
[node recursivelyDisplay];
|
||||
}
|
||||
|
||||
[self display];
|
||||
}
|
||||
|
||||
- (void)displayImmediately
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
@@ -91,22 +91,6 @@
|
||||
return sizingQueue;
|
||||
}
|
||||
|
||||
+ (UIView *)workingView
|
||||
{
|
||||
// we add nodes' views to this invisible window to start async rendering
|
||||
static UIWindow *workingWindow = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
workingWindow = [[UIWindow alloc] initWithFrame:CGRectZero];
|
||||
workingWindow.windowLevel = UIWindowLevelNormal - 1000;
|
||||
workingWindow.userInteractionEnabled = NO;
|
||||
workingWindow.clipsToBounds = YES;
|
||||
workingWindow.hidden = YES;
|
||||
});
|
||||
|
||||
return workingWindow;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Helpers.
|
||||
@@ -191,47 +175,51 @@ static BOOL ASRangeIsValid(NSRange range)
|
||||
NSInteger index = [self indexForIndexPath:node.asyncdisplaykit_indexPath];
|
||||
if (NSLocationInRange(index, _workingRange)) {
|
||||
// move the node's view to the working range area, so its rendering persists
|
||||
[self moveNodeToWorkingView:node];
|
||||
[self addNodeToWorkingRange:node];
|
||||
} else {
|
||||
// this node isn't in the working range, remove it from the view hierarchy
|
||||
[self removeNodeFromWorkingView:node];
|
||||
[self removeNodeFromWorkingRange:node];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)removeNodeFromWorkingView:(ASCellNode *)node
|
||||
- (void)removeNodeFromWorkingRange:(ASCellNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert(node, @"invalid argument");
|
||||
|
||||
[node recursiveSetPreventOrCancelDisplay:YES];
|
||||
[node.view removeFromSuperview];
|
||||
|
||||
|
||||
// since this class usually manages large or infinite data sets, the working range
|
||||
// directly bounds memory usage by requiring redrawing any content that falls outside the range.
|
||||
[node recursivelyReclaimMemory];
|
||||
|
||||
|
||||
[_workingIndexPaths removeObject:node.asyncdisplaykit_indexPath];
|
||||
}
|
||||
|
||||
- (void)moveNodeToWorkingView:(ASCellNode *)node
|
||||
- (void)addNodeToWorkingRange:(ASCellNode *)node
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert(node, @"invalid argument");
|
||||
|
||||
[self moveNode:node toView:[ASRangeController workingView]];
|
||||
// if node is in the working range it should not actively be in view
|
||||
[node.view removeFromSuperview];
|
||||
|
||||
[node recursivelyDisplay];
|
||||
|
||||
[_workingIndexPaths addObject:node.asyncdisplaykit_indexPath];
|
||||
}
|
||||
|
||||
- (void)moveNode:(ASCellNode *)node toView:(UIView *)view
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert(node && view, @"invalid argument, did you mean -removeNodeFromWorkingView:?");
|
||||
ASDisplayNodeAssert(node && view, @"invalid argument, did you mean -removeNodeFromWorkingRange:?");
|
||||
|
||||
// use an explicit transaction to force CoreAnimation to display nodes in the order they are added.
|
||||
[CATransaction begin];
|
||||
|
||||
[view addSubview:node.view];
|
||||
|
||||
|
||||
[CATransaction commit];
|
||||
}
|
||||
|
||||
@@ -481,7 +469,7 @@ static NSRange ASCalculateWorkingRange(ASRangeTuningParameters params, ASScrollD
|
||||
_nodeSizes,
|
||||
[_delegate rangeControllerViewportSize:self]);
|
||||
}
|
||||
|
||||
|
||||
[self setWorkingRange:workingRange];
|
||||
}
|
||||
|
||||
@@ -504,7 +492,7 @@ static NSRange ASCalculateWorkingRange(ASRangeTuningParameters params, ASScrollD
|
||||
for (NSIndexPath *indexPath in removedIndexPaths) {
|
||||
ASCellNode *node = [self sizedNodeForIndexPath:indexPath];
|
||||
ASDisplayNodeAssert(node, @"an unsized node should never have entered the working range");
|
||||
[self removeNodeFromWorkingView:node];
|
||||
[self removeNodeFromWorkingRange:node];
|
||||
}
|
||||
|
||||
// add nodes that have entered the working range (i.e., those that are in the new working range but not the old one)
|
||||
@@ -513,7 +501,7 @@ static NSRange ASCalculateWorkingRange(ASRangeTuningParameters params, ASScrollD
|
||||
// if a node in the working range is still sizing, the sizing logic will add it to the working range for us later
|
||||
ASCellNode *node = [self sizedNodeForIndexPath:indexPath];
|
||||
if (node) {
|
||||
[self moveNodeToWorkingView:node];
|
||||
[self addNodeToWorkingRange:node];
|
||||
} else {
|
||||
ASDisplayNodeAssert(_sizedNodeCount != _totalNodeCount, @"logic error");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user