diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b83bea1..f7267c24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - [ASTextNode2] Provide compile flag to globally enable new implementation of ASTextNode: ASTEXTNODE_EXPERIMENT_GLOBAL_ENABLE. [Scott Goodson](https://github.com/appleguy) [#396](https://github.com/TextureGroup/Texture/pull/410) - Add ASCollectionGalleryLayoutDelegate - an async collection layout that makes same-size collections (e.g photo galleries, pagers, etc) fast and lightweight! [Huy Nguyen](https://github.com/nguyenhuy/) [#76](https://github.com/TextureGroup/Texture/pull/76) [#451](https://github.com/TextureGroup/Texture/pull/451) - Fix an issue that causes infinite layout loop in ASDisplayNode after [#428](https://github.com/TextureGroup/Texture/pull/428) [Huy Nguyen](https://github.com/nguyenhuy) [#455](https://github.com/TextureGroup/Texture/pull/455) +- Fix an issue in layout transition that causes it to unexpectedly use the old layout [Huy Nguyen](https://github.com/nguyenhuy) [#464](https://github.com/TextureGroup/Texture/pull/464) ##2.3.5 - Fix an issue where inserting/deleting sections could lead to inconsistent supplementary element behavior. [Adlai Holler](https://github.com/Adlai-Holler) diff --git a/Source/ASDisplayNode+Layout.mm b/Source/ASDisplayNode+Layout.mm index 6d44b4a1..31f0739c 100644 --- a/Source/ASDisplayNode+Layout.mm +++ b/Source/ASDisplayNode+Layout.mm @@ -185,6 +185,11 @@ ASPrimitiveTraitCollectionDeprecatedImplementation - (ASSizeRange)constrainedSizeForCalculatedLayout { ASDN::MutexLocker l(__instanceLock__); + return [self _locked_constrainedSizeForCalculatedLayout]; +} + +- (ASSizeRange)_locked_constrainedSizeForCalculatedLayout +{ if (_pendingDisplayNodeLayout != nullptr) { return _pendingDisplayNodeLayout->constrainedSize; } @@ -478,6 +483,11 @@ ASPrimitiveTraitCollectionDeprecatedImplementation - (BOOL)_isLayoutTransitionInvalid { ASDN::MutexLocker l(__instanceLock__); + return [self _locked_isLayoutTransitionValid]; +} + +- (BOOL)_locked_isLayoutTransitionValid +{ if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) { ASLayoutElementContext *context = ASLayoutElementGetCurrentContext(); if (context == nil || _pendingTransitionID != context.transitionID) { @@ -510,9 +520,6 @@ ASPrimitiveTraitCollectionDeprecatedImplementation measurementCompletion:(void(^)())completion { ASDisplayNodeAssertMainThread(); - - [self setNeedsLayout]; - [self transitionLayoutWithSizeRange:[self _locked_constrainedSizeForLayoutPass] animated:animated shouldMeasureAsync:shouldMeasureAsync @@ -536,17 +543,28 @@ ASPrimitiveTraitCollectionDeprecatedImplementation return; } - // Check if we are a subnode in a layout transition. - // In this case no measurement is needed as we're part of the layout transition. - if ([self _isLayoutTransitionInvalid]) { - return; - } - + BOOL shouldInvalidateLayout = NO; { ASDN::MutexLocker l(__instanceLock__); - ASDisplayNodeAssert(ASHierarchyStateIncludesLayoutPending(_hierarchyState) == NO, @"Can't start a transition when one of the supernodes is performing one."); + + // Check if we are a subnode in a layout transition. + // In this case no measurement is needed as we're part of the layout transition. + if ([self _locked_isLayoutTransitionValid]) { + return; + } + + if (ASHierarchyStateIncludesLayoutPending(_hierarchyState)) { + ASDisplayNodeAssert(NO, @"Can't start a transition when one of the supernodes is performing one."); + return; + } + + shouldInvalidateLayout = ASSizeRangeEqualToSizeRange([self _locked_constrainedSizeForCalculatedLayout], constrainedSize); } - + + if (shouldInvalidateLayout) { + [self setNeedsLayout]; + } + // Every new layout transition has a transition id associated to check in subsequent transitions for cancelling int32_t transitionID = [self _startNewTransition]; as_log_verbose(ASLayoutLog(), "Transition ID is %d", transitionID);