Let ASLayout determine if a node should measure

This commit is contained in:
Levi McCallum
2016-05-20 16:44:44 -07:00
parent c809609b01
commit f809d4a1c9
4 changed files with 26 additions and 15 deletions

View File

@@ -650,10 +650,15 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
} }
} }
// only calculate the size if // Only generate a new layout if:
// - we haven't already // - The current layout is dirty
// - the constrained size range is different // - The passed constrained size is different than the layout's constrained size
return (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange(constrainedSize, _layout.constrainedSizeRange)); return ([self _dirtyLayout] || !ASSizeRangeEqualToSizeRange(constrainedSize, _layout.constrainedSizeRange));
}
- (BOOL)_dirtyLayout
{
return _layout == nil || _layout.isDirty;
} }
#pragma mark - Layout Transition #pragma mark - Layout Transition
@@ -1019,7 +1024,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
ASDisplayNodeAssertThreadAffinity(self); ASDisplayNodeAssertThreadAffinity(self);
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
if (!_flags.isMeasured) { if ([self _dirtyLayout]) {
return; return;
} }
@@ -1095,7 +1100,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
// Normally measure will be called before layout occurs. If this doesn't happen, nothing is going to call it at all. // Normally measure will be called before layout occurs. If this doesn't happen, nothing is going to call it at all.
// We simply call measureWithSizeRange: using a size range equal to whatever bounds were provided to that element or // We simply call measureWithSizeRange: using a size range equal to whatever bounds were provided to that element or
// try to measure the node with the largest size as possible // try to measure the node with the largest size as possible
if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && !_flags.isMeasured) { if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && [self _dirtyLayout] == NO) {
if (CGRectEqualToRect(bounds, CGRectZero)) { if (CGRectEqualToRect(bounds, CGRectZero)) {
LOG(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self); LOG(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self);
} else { } else {
@@ -1108,7 +1113,7 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
{ {
ASDisplayNodeAssertMainThread(); ASDisplayNodeAssertMainThread();
if (!_flags.isMeasured) { if ([self _dirtyLayout]) {
return; return;
} }
@@ -2058,8 +2063,10 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
- (void)invalidateCalculatedLayout - (void)invalidateCalculatedLayout
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
// This will cause -measureWithSizeRange: to actually compute the size instead of returning the previously cached size
_flags.isMeasured = NO; // This will cause the next call to -measureWithSizeRange: to actually compute a new layout
// instead of returning the current layout
_layout.dirty = YES;
} }
- (void)__didLoad - (void)__didLoad
@@ -2395,8 +2402,7 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
} }
} }
- (void)applyLayout:(ASLayout *)layout - (void)applyLayout:(ASLayout *)layout layoutContext:(ASLayoutTransition *)layoutContext
layoutContext:(ASLayoutTransition *)layoutContext
{ {
ASDN::MutexLocker l(_propertyLock); ASDN::MutexLocker l(_propertyLock);
_layout = layout; _layout = layout;
@@ -2405,8 +2411,6 @@ void recursivelyTriggerDisplayForLayer(CALayer *layer, BOOL shouldBlock)
ASDisplayNodeAssertTrue(layout.size.width >= 0.0); ASDisplayNodeAssertTrue(layout.size.width >= 0.0);
ASDisplayNodeAssertTrue(layout.size.height >= 0.0); ASDisplayNodeAssertTrue(layout.size.height >= 0.0);
_flags.isMeasured = YES;
if (self.usesImplicitHierarchyManagement && layoutContext != nil) { if (self.usesImplicitHierarchyManagement && layoutContext != nil) {
[layoutContext applySubnodeInsertions]; [layoutContext applySubnodeInsertions];
[layoutContext applySubnodeRemovals]; [layoutContext applySubnodeRemovals];

View File

@@ -21,7 +21,9 @@ extern CGPoint const CGPointNull;
extern BOOL CGPointIsNull(CGPoint point); extern BOOL CGPointIsNull(CGPoint point);
/** Represents a computed immutable layout tree. */ /**
* A node in the layout tree that represents the size and position of the object that created it (ASLayoutable).
*/
@interface ASLayout : NSObject @interface ASLayout : NSObject
/** /**
@@ -56,6 +58,11 @@ extern BOOL CGPointIsNull(CGPoint point);
*/ */
@property (nonatomic, readonly) NSArray<ASLayout *> *immediateSublayouts; @property (nonatomic, readonly) NSArray<ASLayout *> *immediateSublayouts;
/**
* Mark the layout dirty for future regeneration.
*/
@property (nonatomic, getter=isDirty) BOOL dirty;
/** /**
* A boolean describing if the current layout has been flattened. * A boolean describing if the current layout has been flattened.
*/ */

View File

@@ -50,6 +50,7 @@ extern BOOL CGPointIsNull(CGPoint point)
} }
l->_constrainedSizeRange = sizeRange; l->_constrainedSizeRange = sizeRange;
l->_size = size; l->_size = size;
l->_dirty = NO;
if (CGPointIsNull(position) == NO) { if (CGPointIsNull(position) == NO) {
l->_position = CGPointMake(ASCeilPixelValue(position.x), ASCeilPixelValue(position.y)); l->_position = CGPointMake(ASCeilPixelValue(position.x), ASCeilPixelValue(position.y));

View File

@@ -82,7 +82,6 @@ FOUNDATION_EXPORT NSString * const ASRenderingEngineDidDisplayNodesScheduledBefo
unsigned implementsDrawParameters:1; unsigned implementsDrawParameters:1;
// internal state // internal state
unsigned isMeasured:1;
unsigned isEnteringHierarchy:1; unsigned isEnteringHierarchy:1;
unsigned isExitingHierarchy:1; unsigned isExitingHierarchy:1;
unsigned isInHierarchy:1; unsigned isInHierarchy:1;