[ASDisplayNode+Layout] In layoutThatFits:, check and use _pending layout if valid. (#413)

I believe this check is supposed to be here. Unit tests pass with it in place.
Without it, calling layoutThatFits: (as ASDataController does) and then calling
it again later (as ASCollectionNode does when answering the sizeForItem: call)
will recompute the layout, potentially on main.

This seems to have more of an impact / benefit for Yoga layouts, but I don't think
its benefit is exclusive to them.
This commit is contained in:
appleguy 2017-07-05 03:02:38 -07:00 committed by Huy Nguyen
parent 5d72a76fb9
commit fb6cad941f

View File

@ -73,7 +73,7 @@
- (ASLayout *)layoutThatFits:(ASSizeRange)constrainedSize parentSize:(CGSize)parentSize
{
ASDN::MutexLocker l(__instanceLock__);
// 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
@ -81,23 +81,26 @@
return [self calculateLayoutThatFits:constrainedSize restrictedToSize:self.style.size relativeToParentSize:parentSize];
}
ASLayout *layout = nil;
if (_calculatedDisplayNodeLayout->isValidForConstrainedSizeParentSize(constrainedSize, parentSize)) {
ASDisplayNodeAssertNotNil(_calculatedDisplayNodeLayout->layout, @"-[ASDisplayNode layoutThatFits:parentSize:] _calculatedDisplayNodeLayout->layout should not be nil! %@", self);
// Our calculated layout is suitable for this constrainedSize, so keep using it and
// invalidate any pending layout that has been generated in the past.
_pendingDisplayNodeLayout = nullptr;
return _calculatedDisplayNodeLayout->layout ?: [ASLayout layoutWithLayoutElement:self size:{0, 0}];
layout = _calculatedDisplayNodeLayout->layout;
} else if (_pendingDisplayNodeLayout != nullptr && _pendingDisplayNodeLayout->isValidForConstrainedSizeParentSize(constrainedSize, parentSize)) {
ASDisplayNodeAssertNotNil(_pendingDisplayNodeLayout->layout, @"-[ASDisplayNode layoutThatFits:parentSize:] _pendingDisplayNodeLayout->layout should not be nil! %@", self);
layout = _pendingDisplayNodeLayout->layout;
} else {
// Create a pending display node layout for the layout pass
layout = [self calculateLayoutThatFits:constrainedSize
restrictedToSize:self.style.size
relativeToParentSize:parentSize];
_pendingDisplayNodeLayout = std::make_shared<ASDisplayNodeLayout>(layout, constrainedSize, parentSize);
ASDisplayNodeAssertNotNil(layout, @"-[ASDisplayNode layoutThatFits:parentSize:] newly calculated layout should not be nil! %@", self);
}
// Create a pending display node layout for the layout pass
_pendingDisplayNodeLayout = std::make_shared<ASDisplayNodeLayout>(
[self calculateLayoutThatFits:constrainedSize restrictedToSize:self.style.size relativeToParentSize:parentSize],
constrainedSize,
parentSize
);
ASDisplayNodeAssertNotNil(_pendingDisplayNodeLayout->layout, @"-[ASDisplayNode layoutThatFits:parentSize:] _pendingDisplayNodeLayout->layout should not be nil! %@", self);
return _pendingDisplayNodeLayout->layout ?: [ASLayout layoutWithLayoutElement:self size:{0, 0}];
return layout ?: [ASLayout layoutWithLayoutElement:self size:{0, 0}];
}
#pragma mark ASLayoutElementStyleExtensibility