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)
+ (BOOL)shouldUseNewRenderingRange;
+ (void)setShouldUseNewRenderingRange:(BOOL)shouldUseNewRenderingRange;
/** @name Layout */

View File

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

View File

@ -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]) {
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
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];
#else
[node recursivelyEnsureDisplay]; // Need to do this without waiting
#endif
}
}
- (void)node:(ASDisplayNode *)node exitedRangeOfType:(ASLayoutRangeType)rangeType
@ -100,7 +101,13 @@
// The node calls clearCurrentContents and suspends display
[node exitInterfaceState:ASInterfaceStateDisplay];
#if USE_WORKING_WINDOW
if (![ASDisplayNode shouldUseNewRenderingRange]) {
if (![node isLayerBacked]) {
[node.view removeFromSuperview];
} else {
[node.layer removeFromSuperlayer];
}
} 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]) {
@ -112,13 +119,7 @@
// 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 {
[node.layer removeFromSuperlayer];
}
#endif
}
@end

View File

@ -20,10 +20,6 @@
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.
Examples include rasterization and external driving of the .interfaceState property.

View File

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