Add ability to enable new rendering range with a class method in ASDisplayNode+Beta.h

This commit is contained in:
Scott Goodson 2015-12-26 14:22:24 -08:00
parent 830659b561
commit a1429ea23b
5 changed files with 50 additions and 38 deletions

View File

@ -8,6 +8,9 @@
@interface ASDisplayNode (Beta) @interface ASDisplayNode (Beta)
+ (BOOL)shouldUseNewRenderingRange;
+ (void)setShouldUseNewRenderingRange:(BOOL)shouldUseNewRenderingRange;
/** @name Layout */ /** @name Layout */

View File

@ -1560,6 +1560,17 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
return _flags.shouldBypassEnsureDisplay; return _flags.shouldBypassEnsureDisplay;
} }
static BOOL ShouldUseNewRenderingRange = NO;
+ (BOOL)shouldUseNewRenderingRange
{
return ShouldUseNewRenderingRange;
}
+ (void)setShouldUseNewRenderingRange:(BOOL)shouldUseNewRenderingRange
{
ShouldUseNewRenderingRange = shouldUseNewRenderingRange;
}
#pragma mark - For Subclasses #pragma mark - For Subclasses
- (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize

View File

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

View File

@ -20,10 +20,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
// Project-wide control for whether the offscreen UIWindow is used for display, or if
// ASDK's internal system for coalescing and triggering display events is used.
#define USE_WORKING_WINDOW 1
/** /**
Hierarchy state is propogated from nodes to all of their children when certain behaviors are required from the subtree. Hierarchy state is propogated from nodes to all of their children when certain behaviors are required from the subtree.
Examples include rasterization and external driving of the .interfaceState property. Examples include rasterization and external driving of the .interfaceState property.

View File

@ -13,6 +13,7 @@
#import "ASDisplayNodeInternal.h" #import "ASDisplayNodeInternal.h"
#import "ASDisplayNode+Subclasses.h" #import "ASDisplayNode+Subclasses.h"
#import "ASDisplayNode+FrameworkPrivate.h" #import "ASDisplayNode+FrameworkPrivate.h"
#import "ASDisplayNode+Beta.h"
#import "ASEqualityHelpers.h" #import "ASEqualityHelpers.h"
/** /**
@ -248,11 +249,11 @@
_messageToViewOrLayer(setNeedsDisplay); _messageToViewOrLayer(setNeedsDisplay);
#if !USE_WORKING_WINDOW if ([ASDisplayNode shouldUseNewRenderingRange]) {
if (_layer && !self.isSynchronous) { if (_layer && !self.isSynchronous) {
[ASDisplayNode scheduleNodeForDisplay:self]; [ASDisplayNode scheduleNodeForDisplay:self];
}
} }
#endif
} }
} }