Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a bug with Yoga nodes whose position change and don't update. #1408

Merged
merged 1 commit into from
Mar 22, 2019
Merged
Show file tree
Hide file tree
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
10 changes: 10 additions & 0 deletions Source/ASDisplayNode+Layout.mm
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,19 @@ - (void)_u_measureNodeWithBoundsIfNecessary:(CGRect)bounds
// Use the last known constrainedSize passed from a parent during layout (if never, use bounds).
NSUInteger version = _layoutVersion;
ASSizeRange constrainedSize = [self _locked_constrainedSizeForLayoutPass];
#if YOGA
// This flag indicates to the Texture+Yoga code that this next layout is intended to be
// displayed (vs. just for measurement). This will cause it to call setNeedsLayout on any nodes
// whose layout changes as a result of the Yoga recalculation. This is necessary because a
// change in one Yoga node can change the layout for any other node in the tree.
self.willApplyNextYogaCalculatedLayout = YES;
#endif
ASLayout *layout = [self calculateLayoutThatFits:constrainedSize
restrictedToSize:self.style.size
relativeToParentSize:boundsSizeForLayout];
#if YOGA
self.willApplyNextYogaCalculatedLayout = NO;
#endif
nextLayout = ASDisplayNodeLayout(layout, constrainedSize, boundsSizeForLayout, version);
// Now that the constrained size of pending layout might have been reused, the layout is useless
// Release it and any orphaned subnodes it retains
Expand Down
3 changes: 2 additions & 1 deletion Source/ASDisplayNode+Yoga.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ AS_EXTERN void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullab
@property BOOL yogaLayoutInProgress;
// TODO: Make this atomic (lock).
@property (nullable, nonatomic) ASLayout *yogaCalculatedLayout;
@property (nonatomic) BOOL willApplyNextYogaCalculatedLayout;

// Will walk up the Yoga tree and returns the root node
- (ASDisplayNode *)yogaRoot;
Expand All @@ -54,7 +55,7 @@ AS_EXTERN void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullab
/// For internal usage only
- (ASLayout *)calculateLayoutYoga:(ASSizeRange)constrainedSize;
/// For internal usage only
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize;
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize willApply:(BOOL)willApply;
/// For internal usage only
- (void)invalidateCalculatedYogaLayout;
/**
Expand Down
25 changes: 20 additions & 5 deletions Source/ASDisplayNode+Yoga.mm
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ - (ASLayout *)yogaCalculatedLayout
return _yogaCalculatedLayout;
}

- (BOOL)willApplyNextYogaCalculatedLayout {
return _willApplyNextYogaCalculatedLayout;
}

- (void)setWillApplyNextYogaCalculatedLayout:(BOOL)willApplyNextYogaCalculatedLayout {
_willApplyNextYogaCalculatedLayout = willApplyNextYogaCalculatedLayout;
}

- (void)setYogaLayoutInProgress:(BOOL)yogaLayoutInProgress
{
setFlag(YogaLayoutInProgress, yogaLayoutInProgress);
Expand Down Expand Up @@ -194,7 +202,7 @@ - (ASLayout *)layoutForYogaNode
return [ASLayout layoutWithLayoutElement:self size:size position:position sublayouts:nil];
}

- (void)setupYogaCalculatedLayout
- (void)setupYogaCalculatedLayoutAndSetNeedsLayoutForChangedNodes:(BOOL)setNeedsLayoutForChangedNodes
{
ASScopedLockSelfOrToRoot();

Expand Down Expand Up @@ -231,6 +239,13 @@ - (void)setupYogaCalculatedLayout
layout = [layout filteredNodeLayoutTree];

if ([self.yogaCalculatedLayout isEqual:layout] == NO) {
if (setNeedsLayoutForChangedNodes && !self.willApplyNextYogaCalculatedLayout) {
// This flag will be set when this layout is intended for immediate display. In this case, we
// want to ensure that we call setNeedsLayout on any other nodes. Note that we skip any nodes
// whose willApplyNextYogaCalculatedLayout flags are set, as those are the nodes that are
// already being laid out.
[self setNeedsLayout];
}
self.yogaCalculatedLayout = layout;
} else {
layout = self.yogaCalculatedLayout;
Expand Down Expand Up @@ -320,7 +335,7 @@ - (ASLayout *)calculateLayoutYoga:(ASSizeRange)constrainedSize
if (self.yogaLayoutInProgress == NO) {
ASYogaLog("Calculating yoga layout from root %@, %@", self,
NSStringFromASSizeRange(constrainedSize));
[self calculateLayoutFromYogaRoot:constrainedSize];
[self calculateLayoutFromYogaRoot:constrainedSize willApply:self.willApplyNextYogaCalculatedLayout];
} else {
ASYogaLog("Reusing existing yoga layout %@", _yogaCalculatedLayout);
}
Expand All @@ -337,15 +352,15 @@ - (ASLayout *)calculateLayoutYoga:(ASSizeRange)constrainedSize
return [self calculateLayoutLayoutSpec:constrainedSize];
}

- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
- (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize willApply:(BOOL)willApply
{
ASScopedLockSet lockSet = [self lockToRootIfNeededForLayout];
ASDisplayNode *yogaRoot = self.yogaRoot;

if (self != yogaRoot) {
ASYogaLog("ESCALATING to Yoga root: %@", self);
// TODO(appleguy): Consider how to get the constrainedSize for the yogaRoot when escalating manually.
[yogaRoot calculateLayoutFromYogaRoot:ASSizeRangeUnconstrained];
[yogaRoot calculateLayoutFromYogaRoot:ASSizeRangeUnconstrained willApply:willApply];
return;
}

Expand Down Expand Up @@ -398,7 +413,7 @@ - (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
});

ASDisplayNodePerformBlockOnEveryYogaChild(self, ^(ASDisplayNode * _Nonnull node) {
[node setupYogaCalculatedLayout];
[node setupYogaCalculatedLayoutAndSetNeedsLayoutForChangedNodes:willApply];
node.yogaLayoutInProgress = NO;
});

Expand Down
1 change: 1 addition & 0 deletions Source/Private/ASDisplayNodeInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ AS_EXTERN NSString * const ASRenderingEngineDidDisplayNodesScheduledBeforeTimest
NSMutableArray<ASDisplayNode *> *_yogaChildren;
__weak ASDisplayNode *_yogaParent;
ASLayout *_yogaCalculatedLayout;
BOOL _willApplyNextYogaCalculatedLayout;
#endif

// Automatically manages subnodes
Expand Down