Skip to content
This repository has been archived by the owner on Feb 2, 2023. It is now read-only.

[Layout Transition] Layout Transition Fixes #2657

Merged
merged 2 commits into from
Nov 28, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 20 additions & 14 deletions AsyncDisplayKit/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ - (void)_initializeInstance

_defaultLayoutTransitionDuration = 0.2;
_defaultLayoutTransitionDelay = 0.0;
_defaultLayoutTransitionOptions = UIViewAnimationOptionBeginFromCurrentState;
_defaultLayoutTransitionOptions = UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionTransitionNone;

_flags.canClearContentsOfLayer = YES;
_flags.canCallSetNeedsDisplayOfLayer = YES;
Expand Down Expand Up @@ -878,12 +878,13 @@ - (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize parentSize:(CGSize)par
{
ASDN::MutexLocker l(__instanceLock__);

// If multiple layout transitions are in progress it can happen that an invalid one is still trying to do a measurement
// before it get's cancelled. In this case we should not touch any layout and return a no op layout
// If one or multiple layout transitions are in flight it still can happen that layout information is requested
// on other threads. As the pending and calculated layout to be updated in the layout transition in here just a
// layout calculation wil be performed without side effect
if ([self _isLayoutTransitionInvalid]) {
return [ASLayout layoutWithLayoutElement:self size:{0, 0}];
return [self calculateLayoutThatFits:constrainedSize restrictedToSize:self.style.size relativeToParentSize:parentSize];
}

if (_calculatedDisplayNodeLayout->isValidForConstrainedSizeParentSize(constrainedSize, parentSize)) {
ASDisplayNodeAssertNotNil(_calculatedDisplayNodeLayout->layout, @"-[ASDisplayNode layoutThatFits:parentSize:] _calculatedDisplayNodeLayout->layout should not be nil! %@", self);
return _calculatedDisplayNodeLayout->layout ?: [ASLayout layoutWithLayoutElement:self size:{0, 0}];
Expand Down Expand Up @@ -933,8 +934,7 @@ - (void)transitionLayoutWithAnimation:(BOOL)animated
ASDisplayNodeAssertMainThread();

[self setNeedsLayout];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maicki Make a note about trying if we can just call invalidateLayout here -- since we probably don't want the layer-driven layout pass from this anyway. Love this diff, great solution!

[self.view layoutIfNeeded];


[self transitionLayoutWithSizeRange:[self _locked_constrainedSizeForLayoutPass]
animated:animated
shouldMeasureAsync:shouldMeasureAsync
Expand Down Expand Up @@ -1029,8 +1029,6 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize
[node _completePendingLayoutTransition];
node.hierarchyState &= (~ASHierarchyStateLayoutPending);
});

[self _finishOrCancelTransition];

// Measurement pass completion
if (completion) {
Expand All @@ -1051,6 +1049,9 @@ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize

// Kick off animating the layout transition
[self animateLayoutTransition:_pendingLayoutTransitionContext];

// Mark transaction as finished
[self _finishOrCancelTransition];
});
};

Expand Down Expand Up @@ -1574,7 +1575,13 @@ - (void)__layout
LOG(@"Warning: No size given for node before node was trying to layout itself: %@. Please provide a frame for the node.", self);
return;
}


// If a current layout transition is in progress there is no need to do a measurement and layout pass in here as
// this is supposed to happen within the layout transition process
if ([self _isTransitionInProgress]) {
return;
}

// This method will confirm that the layout is up to date (and update if needed).
// Importantly, it will also APPLY the layout to all of our subnodes if (unless parent is transitioning).
[self _locked_measureNodeWithBoundsIfNecessary:bounds];
Expand Down Expand Up @@ -1685,14 +1692,13 @@ - (ASSizeRange)_locked_constrainedSizeForLayoutPass
CGSize boundsSizeForLayout = ASCeilSizeValues(self.threadSafeBounds.size);

// Checkout if constrained size of pending or calculated display node layout can be used
if (_pendingDisplayNodeLayout != nullptr
&& (_pendingDisplayNodeLayout->requestedLayoutFromAbove
|| CGSizeEqualToSize(_pendingDisplayNodeLayout->layout.size, boundsSizeForLayout))) {
if (_pendingDisplayNodeLayout != nullptr
&& CGSizeEqualToSize(_pendingDisplayNodeLayout->layout.size, boundsSizeForLayout)) {
// We assume the size from the last returned layoutThatFits: layout was applied so use the pending display node
// layout constrained size
return _pendingDisplayNodeLayout->constrainedSize;
} else if (_calculatedDisplayNodeLayout->layout != nil
&& (_calculatedDisplayNodeLayout->requestedLayoutFromAbove
&& (_calculatedDisplayNodeLayout->requestedLayoutFromAbove == NO
|| CGSizeEqualToSize(_calculatedDisplayNodeLayout->layout.size, boundsSizeForLayout))) {
// We assume the _calculatedDisplayNodeLayout is still valid and the frame is not different
return _calculatedDisplayNodeLayout->constrainedSize;
Expand Down