@@ -616,25 +616,20 @@ - (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
616616 [self cancelLayoutTransitionsInProgress ];
617617
618618 ASLayout *previousLayout = _layout;
619- ASSizeRange previousConstrainedSize = _constrainedSize;
620619 ASLayout *newLayout = [self calculateLayoutThatFits: constrainedSize];
621620
622621 if (ASHierarchyStateIncludesLayoutPending (_hierarchyState)) {
623622 _pendingLayoutTransition = [[ASLayoutTransition alloc ] initWithNode: self
624623 pendingLayout: newLayout
625- pendingConstrainedSize: constrainedSize
626- previousLayout: previousLayout
627- previousConstrainedSize: previousConstrainedSize];
624+ previousLayout: previousLayout];
628625 } else {
629626 ASLayoutTransition *layoutContext;
630627 if (self.usesImplicitHierarchyManagement ) {
631628 layoutContext = [[ASLayoutTransition alloc ] initWithNode: self
632629 pendingLayout: newLayout
633- pendingConstrainedSize: constrainedSize
634- previousLayout: previousLayout
635- previousConstrainedSize: previousConstrainedSize];
630+ previousLayout: previousLayout];
636631 }
637- [self applyLayout: newLayout constrainedSize: constrainedSize layoutContext: layoutContext];
632+ [self applyLayout: newLayout layoutContext: layoutContext];
638633 [self _completeLayoutCalculation ];
639634 }
640635
@@ -655,10 +650,15 @@ - (BOOL)shouldMeasureWithSizeRange:(ASSizeRange)constrainedSize
655650 }
656651 }
657652
658- // only calculate the size if
659- // - we haven't already
660- // - the constrained size range is different
661- return (!_flags.isMeasured || !ASSizeRangeEqualToSizeRange (constrainedSize, _constrainedSize));
653+ // Only generate a new layout if:
654+ // - The current layout is dirty
655+ // - The passed constrained size is different than the layout's constrained size
656+ return ([self _hasDirtyLayout ] || !ASSizeRangeEqualToSizeRange (constrainedSize, _layout.constrainedSizeRange ));
657+ }
658+
659+ - (BOOL )_hasDirtyLayout
660+ {
661+ return _layout == nil || _layout.isDirty ;
662662}
663663
664664#pragma mark - Layout Transition
@@ -667,9 +667,8 @@ - (void)transitionLayoutWithAnimation:(BOOL)animated
667667 shouldMeasureAsync : (BOOL )shouldMeasureAsync
668668 measurementCompletion : (void (^)())completion
669669{
670- ASSizeRange currentConstrainedSize = _constrainedSize;
671670 [self invalidateCalculatedLayout ];
672- [self transitionLayoutWithSizeRange: currentConstrainedSize
671+ [self transitionLayoutWithSizeRange: _layout.constrainedSizeRange
673672 animated: animated
674673 shouldMeasureAsync: shouldMeasureAsync
675674 measurementCompletion: completion];
@@ -732,8 +731,7 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
732731 }
733732
734733 ASLayout *previousLayout = _layout;
735- ASSizeRange previousConstrainedSize = _constrainedSize;
736- [self applyLayout: newLayout constrainedSize: constrainedSize layoutContext: nil ];
734+ [self applyLayout: newLayout layoutContext: nil ];
737735
738736 ASDisplayNodePerformBlockOnEverySubnode (self, ^(ASDisplayNode * _Nonnull node) {
739737 [node applyPendingLayoutContext ];
@@ -749,9 +747,7 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
749747
750748 _pendingLayoutTransition = [[ASLayoutTransition alloc ] initWithNode: self
751749 pendingLayout: newLayout
752- pendingConstrainedSize: constrainedSize
753- previousLayout: previousLayout
754- previousConstrainedSize: previousConstrainedSize];
750+ previousLayout: previousLayout];
755751 [_pendingLayoutTransition applySubnodeInsertions ];
756752
757753 _transitionContext = [[_ASTransitionContext alloc ] initWithAnimation: animated
@@ -1028,11 +1024,10 @@ - (void)__setNeedsLayout
10281024 ASDisplayNodeAssertThreadAffinity (self);
10291025 ASDN::MutexLocker l (_propertyLock);
10301026
1031- if (!_flags. isMeasured ) {
1027+ if ([ self _hasDirtyLayout ] ) {
10321028 return ;
10331029 }
10341030
1035- ASSizeRange oldConstrainedSize = _constrainedSize;
10361031 [self invalidateCalculatedLayout ];
10371032
10381033 if (_supernode) {
@@ -1045,7 +1040,7 @@ - (void)__setNeedsLayout
10451040 }
10461041
10471042 // This is the root node. Trigger a full measurement pass on *current* thread. Old constrained size is re-used.
1048- [self measureWithSizeRange: oldConstrainedSize ];
1043+ [self measureWithSizeRange: _layout.constrainedSizeRange ];
10491044
10501045 CGRect oldBounds = self.bounds ;
10511046 CGSize oldSize = oldBounds.size ;
@@ -1105,7 +1100,7 @@ - (void)measureNodeWithBoundsIfNecessary:(CGRect)bounds
11051100 // Normally measure will be called before layout occurs. If this doesn't happen, nothing is going to call it at all.
11061101 // We simply call measureWithSizeRange: using a size range equal to whatever bounds were provided to that element or
11071102 // try to measure the node with the largest size as possible
1108- if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && !_flags. isMeasured ) {
1103+ if (self.supernode == nil && !self.supportsRangeManagedInterfaceState && [ self _hasDirtyLayout ] == NO ) {
11091104 if (CGRectEqualToRect (bounds, CGRectZero)) {
11101105 LOG (@" Warning: No size given for node before node was trying to layout itself: %@ . Please provide a frame for the node." , self);
11111106 } else {
@@ -1118,7 +1113,7 @@ - (void)layout
11181113{
11191114 ASDisplayNodeAssertMainThread ();
11201115
1121- if (!_flags. isMeasured ) {
1116+ if ([ self _hasDirtyLayout ] ) {
11221117 return ;
11231118 }
11241119
@@ -1956,7 +1951,10 @@ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
19561951 // Make sure layoutableObject of the root layout is `self`, so that the flattened layout will be structurally correct.
19571952 if (layout.layoutableObject != self) {
19581953 layout.position = CGPointZero;
1959- layout = [ASLayout layoutWithLayoutableObject: self size: layout.size sublayouts: @[layout]];
1954+ layout = [ASLayout layoutWithLayoutableObject: self
1955+ constrainedSizeRange: constrainedSize
1956+ size: layout.size
1957+ sublayouts: @[layout]];
19601958 }
19611959 return [layout flattenedLayoutUsingPredicateBlock: ^BOOL (ASLayout *evaluatedLayout) {
19621960 if (self.usesImplicitHierarchyManagement ) {
@@ -1969,7 +1967,9 @@ - (ASLayout *)calculateLayoutThatFits:(ASSizeRange)constrainedSize
19691967 // If neither -layoutSpecThatFits: nor -calculateSizeThatFits: is overridden by subclassses, preferredFrameSize should be used,
19701968 // assume that the default implementation of -calculateSizeThatFits: returns it.
19711969 CGSize size = [self calculateSizeThatFits: constrainedSize.max];
1972- return [ASLayout layoutWithLayoutableObject: self size: ASSizeRangeClamp (constrainedSize, size)];
1970+ return [ASLayout layoutWithLayoutableObject: self
1971+ constrainedSizeRange: constrainedSize
1972+ size: ASSizeRangeClamp (constrainedSize, size)];
19731973 }
19741974}
19751975
@@ -2009,7 +2009,7 @@ - (CGSize)calculatedSize
20092009- (ASSizeRange)constrainedSizeForCalculatedLayout
20102010{
20112011 ASDN::MutexLocker l (_propertyLock);
2012- return _constrainedSize ;
2012+ return _layout. constrainedSizeRange ;
20132013}
20142014
20152015- (void )setLayoutSpecBlock : (ASLayoutSpecBlock)layoutSpecBlock
@@ -2063,8 +2063,10 @@ - (UIImage *)placeholderImage
20632063- (void )invalidateCalculatedLayout
20642064{
20652065 ASDN::MutexLocker l (_propertyLock);
2066- // This will cause -measureWithSizeRange: to actually compute the size instead of returning the previously cached size
2067- _flags.isMeasured = NO ;
2066+
2067+ // This will cause the next call to -measureWithSizeRange: to actually compute a new layout
2068+ // instead of returning the current layout
2069+ _layout.dirty = YES ;
20682070}
20692071
20702072- (void )__didLoad
@@ -2395,26 +2397,19 @@ - (void)applyPendingLayoutContext
23952397{
23962398 ASDN::MutexLocker l (_propertyLock);
23972399 if (_pendingLayoutTransition) {
2398- [self applyLayout: _pendingLayoutTransition.pendingLayout
2399- constrainedSize: _pendingLayoutTransition.pendingConstrainedSize
2400- layoutContext: _pendingLayoutTransition];
2400+ [self applyLayout: _pendingLayoutTransition.pendingLayout layoutContext: _pendingLayoutTransition];
24012401 _pendingLayoutTransition = nil ;
24022402 }
24032403}
24042404
2405- - (void )applyLayout : (ASLayout *)layout
2406- constrainedSize : (ASSizeRange)constrainedSize
2407- layoutContext : (ASLayoutTransition *)layoutContext
2405+ - (void )applyLayout : (ASLayout *)layout layoutContext : (ASLayoutTransition *)layoutContext
24082406{
24092407 ASDN::MutexLocker l (_propertyLock);
24102408 _layout = layout;
24112409
24122410 ASDisplayNodeAssertTrue (layout.layoutableObject == self);
24132411 ASDisplayNodeAssertTrue (layout.size .width >= 0.0 );
24142412 ASDisplayNodeAssertTrue (layout.size .height >= 0.0 );
2415-
2416- _constrainedSize = constrainedSize;
2417- _flags.isMeasured = YES ;
24182413
24192414 if (self.usesImplicitHierarchyManagement && layoutContext != nil ) {
24202415 [layoutContext applySubnodeInsertions ];
0 commit comments