|
|
|
|
@@ -11,15 +11,15 @@
|
|
|
|
|
#import "ASDisplayNode.h"
|
|
|
|
|
#import "ASDisplayNode+Subclasses.h"
|
|
|
|
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
|
|
|
|
#import "ASDisplayNode+Beta.h"
|
|
|
|
|
|
|
|
|
|
@interface ASRangeHandlerRender ()
|
|
|
|
|
@property (nonatomic,readonly) UIWindow *workingWindow;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation ASRangeHandlerRender
|
|
|
|
|
|
|
|
|
|
#if USE_WORKING_WINDOW
|
|
|
|
|
@synthesize workingWindow = _workingWindow;
|
|
|
|
|
|
|
|
|
|
- (UIWindow *)workingWindow
|
|
|
|
|
{
|
|
|
|
|
ASDisplayNodeAssertMainThread();
|
|
|
|
|
@@ -28,7 +28,7 @@
|
|
|
|
|
// TODO: Replace this with directly triggering display https://github.com/facebook/AsyncDisplayKit/issues/315
|
|
|
|
|
// Update: Latest attempt is at https://github.com/facebook/AsyncDisplayKit/pull/828
|
|
|
|
|
|
|
|
|
|
if (!_workingWindow) {
|
|
|
|
|
if (!_workingWindow && ![ASDisplayNode shouldUseNewRenderingRange]) {
|
|
|
|
|
_workingWindow = [[UIWindow alloc] initWithFrame:CGRectZero];
|
|
|
|
|
_workingWindow.windowLevel = UIWindowLevelNormal - 1000;
|
|
|
|
|
_workingWindow.userInteractionEnabled = NO;
|
|
|
|
|
@@ -41,12 +41,13 @@
|
|
|
|
|
|
|
|
|
|
- (void)dealloc
|
|
|
|
|
{
|
|
|
|
|
for(CALayer *layer in [self.workingWindow.layer.sublayers copy]) {
|
|
|
|
|
ASDisplayNode *node = layer.asyncdisplaykit_node;
|
|
|
|
|
[self node:node exitedRangeOfType:ASLayoutRangeTypeRender];
|
|
|
|
|
if (![ASDisplayNode shouldUseNewRenderingRange]) {
|
|
|
|
|
for (CALayer *layer in [self.workingWindow.layer.sublayers copy]) {
|
|
|
|
|
ASDisplayNode *node = layer.asyncdisplaykit_node;
|
|
|
|
|
[self node:node exitedRangeOfType:ASLayoutRangeTypeRender];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
- (void)node:(ASDisplayNode *)node enteredRangeOfType:(ASLayoutRangeType)rangeType
|
|
|
|
|
{
|
|
|
|
|
@@ -63,16 +64,16 @@
|
|
|
|
|
[node enterInterfaceState:ASInterfaceStateDisplay];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if USE_WORKING_WINDOW
|
|
|
|
|
// Add the node's layer to an off-screen window to trigger display and mark its contents as non-volatile.
|
|
|
|
|
// Use the layer directly to avoid the substantial overhead of UIView heirarchy manipulations.
|
|
|
|
|
// Any view-backed nodes will still create their views in order to assemble the layer heirarchy, and they will
|
|
|
|
|
// also assemble a view subtree for the node, but we avoid the much more significant expense triggered by a view
|
|
|
|
|
// being added or removed from an onscreen window (responder chain setup, will/DidMoveToWindow: recursive calls, etc)
|
|
|
|
|
[[[self workingWindow] layer] addSublayer:node.layer];
|
|
|
|
|
#else
|
|
|
|
|
[node recursivelyEnsureDisplay]; // Need to do this without waiting
|
|
|
|
|
#endif
|
|
|
|
|
if (![ASDisplayNode shouldUseNewRenderingRange]) {
|
|
|
|
|
[node recursivelyEnsureDisplay]; // Need to do this without waiting
|
|
|
|
|
} else {
|
|
|
|
|
// Add the node's layer to an off-screen window to trigger display and mark its contents as non-volatile.
|
|
|
|
|
// Use the layer directly to avoid the substantial overhead of UIView heirarchy manipulations.
|
|
|
|
|
// Any view-backed nodes will still create their views in order to assemble the layer heirarchy, and they will
|
|
|
|
|
// also assemble a view subtree for the node, but we avoid the much more significant expense triggered by a view
|
|
|
|
|
// being added or removed from an onscreen window (responder chain setup, will/DidMoveToWindow: recursive calls, etc)
|
|
|
|
|
[[[self workingWindow] layer] addSublayer:node.layer];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
|
|
|
|
|
@@ -100,25 +101,25 @@
|
|
|
|
|
// The node calls clearCurrentContents and suspends display
|
|
|
|
|
[node exitInterfaceState:ASInterfaceStateDisplay];
|
|
|
|
|
|
|
|
|
|
#if USE_WORKING_WINDOW
|
|
|
|
|
if (node.layer.superlayer != [[self workingWindow] layer]) {
|
|
|
|
|
// In this case, the node has previously passed through the working range (or it is zero), and it has now fallen outside the working range.
|
|
|
|
|
if (![ASDisplayNode shouldUseNewRenderingRange]) {
|
|
|
|
|
if (![node isLayerBacked]) {
|
|
|
|
|
// If the node is view-backed, we need to make sure to remove the view (which is now present in the containing cell contentsView).
|
|
|
|
|
// Layer-backed nodes will be fully handled by the unconditional removal below.
|
|
|
|
|
[node.view removeFromSuperview];
|
|
|
|
|
} else {
|
|
|
|
|
[node.layer removeFromSuperlayer];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At this point, the node's layer may validly be present either in the workingWindow, or in the contentsView of a cell.
|
|
|
|
|
[node.layer removeFromSuperlayer];
|
|
|
|
|
#else
|
|
|
|
|
if (![node isLayerBacked]) {
|
|
|
|
|
[node.view removeFromSuperview];
|
|
|
|
|
} else {
|
|
|
|
|
if (node.layer.superlayer != [[self workingWindow] layer]) {
|
|
|
|
|
// In this case, the node has previously passed through the working range (or it is zero), and it has now fallen outside the working range.
|
|
|
|
|
if (![node isLayerBacked]) {
|
|
|
|
|
// If the node is view-backed, we need to make sure to remove the view (which is now present in the containing cell contentsView).
|
|
|
|
|
// Layer-backed nodes will be fully handled by the unconditional removal below.
|
|
|
|
|
[node.view removeFromSuperview];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// At this point, the node's layer may validly be present either in the workingWindow, or in the contentsView of a cell.
|
|
|
|
|
[node.layer removeFromSuperlayer];
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|