mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-13 18:00:17 +00:00
[Yoga] Refine the handling of measurement functions when Yoga is used. (#408)
This ensures that measure funcs are not set for container / empty spacer nodes, because Yoga has more internal capabilities than layoutThatFits: knows about. Avoid need for the main layout pass to directly call setup for measure funcs, by making it an implicit part of .yogaLayoutInProgress =. Tear down the measure func after the layout pass to avoid retain cycle.
This commit is contained in:
parent
fcb293e049
commit
1d1a3787c2
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
- (void)setYogaChildren:(NSArray *)yogaChildren
|
- (void)setYogaChildren:(NSArray *)yogaChildren
|
||||||
{
|
{
|
||||||
for (ASDisplayNode *child in _yogaChildren) {
|
for (ASDisplayNode *child in [_yogaChildren copy]) {
|
||||||
// Make sure to un-associate the YGNodeRef tree before replacing _yogaChildren
|
// Make sure to un-associate the YGNodeRef tree before replacing _yogaChildren
|
||||||
// If this becomes a performance bottleneck, it can be optimized by not doing the NSArray removals here.
|
// If this becomes a performance bottleneck, it can be optimized by not doing the NSArray removals here.
|
||||||
[self removeYogaChild:child];
|
[self removeYogaChild:child];
|
||||||
@ -68,14 +68,8 @@
|
|||||||
// Clean up state in case this child had another parent.
|
// Clean up state in case this child had another parent.
|
||||||
[self removeYogaChild:child];
|
[self removeYogaChild:child];
|
||||||
|
|
||||||
BOOL hadZeroChildren = (_yogaChildren.count == 0);
|
|
||||||
|
|
||||||
[_yogaChildren addObject:child];
|
[_yogaChildren addObject:child];
|
||||||
|
|
||||||
// Ensure any measure function is removed before inserting the YGNodeRef child.
|
|
||||||
if (hadZeroChildren) {
|
|
||||||
[self updateYogaMeasureFuncIfNeeded];
|
|
||||||
}
|
|
||||||
// YGNodeRef insertion is done in setParent:
|
// YGNodeRef insertion is done in setParent:
|
||||||
child.yogaParent = self;
|
child.yogaParent = self;
|
||||||
}
|
}
|
||||||
@ -86,15 +80,10 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL hadChildren = (_yogaChildren.count > 0);
|
|
||||||
[_yogaChildren removeObjectIdenticalTo:child];
|
[_yogaChildren removeObjectIdenticalTo:child];
|
||||||
|
|
||||||
// YGNodeRef removal is done in setParent:
|
// YGNodeRef removal is done in setParent:
|
||||||
child.yogaParent = nil;
|
child.yogaParent = nil;
|
||||||
// Ensure any measure function is re-added after removing the YGNodeRef child.
|
|
||||||
if (hadChildren && _yogaChildren.count == 0) {
|
|
||||||
[self updateYogaMeasureFuncIfNeeded];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)semanticContentAttributeDidChange:(UISemanticContentAttribute)attribute
|
- (void)semanticContentAttributeDidChange:(UISemanticContentAttribute)attribute
|
||||||
@ -144,6 +133,7 @@
|
|||||||
- (void)setYogaLayoutInProgress:(BOOL)yogaLayoutInProgress
|
- (void)setYogaLayoutInProgress:(BOOL)yogaLayoutInProgress
|
||||||
{
|
{
|
||||||
setFlag(YogaLayoutInProgress, yogaLayoutInProgress);
|
setFlag(YogaLayoutInProgress, yogaLayoutInProgress);
|
||||||
|
[self updateYogaMeasureFuncIfNeeded];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)yogaLayoutInProgress
|
- (BOOL)yogaLayoutInProgress
|
||||||
@ -184,8 +174,14 @@
|
|||||||
{
|
{
|
||||||
// Size calculation via calculateSizeThatFits: or layoutSpecThatFits:
|
// Size calculation via calculateSizeThatFits: or layoutSpecThatFits:
|
||||||
// This will be used for ASTextNode, as well as any other node that has no Yoga children
|
// This will be used for ASTextNode, as well as any other node that has no Yoga children
|
||||||
id <ASLayoutElement> layoutElementToMeasure = (self.yogaChildren.count == 0 ? self : nil);
|
BOOL isLeafNode = (self.yogaChildren.count == 0);
|
||||||
ASLayoutElementYogaUpdateMeasureFunc(self.style.yogaNode, layoutElementToMeasure);
|
BOOL definesCustomLayout = [self implementsLayoutMethod];
|
||||||
|
|
||||||
|
// We set the measure func only during layout. Otherwise, a cycle is created:
|
||||||
|
// The YGNodeRef Context will retain the ASDisplayNode, which retains the style, which owns the YGNodeRef.
|
||||||
|
BOOL shouldHaveMeasureFunc = (isLeafNode && definesCustomLayout && checkFlag(YogaLayoutInProgress));
|
||||||
|
|
||||||
|
ASLayoutElementYogaUpdateMeasureFunc(self.style.yogaNode, shouldHaveMeasureFunc ? self : nil);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)invalidateCalculatedYogaLayout
|
- (void)invalidateCalculatedYogaLayout
|
||||||
@ -214,7 +210,6 @@
|
|||||||
// Prepare all children for the layout pass with the current Yoga tree configuration.
|
// Prepare all children for the layout pass with the current Yoga tree configuration.
|
||||||
ASDisplayNodePerformBlockOnEveryYogaChild(self, ^(ASDisplayNode * _Nonnull node) {
|
ASDisplayNodePerformBlockOnEveryYogaChild(self, ^(ASDisplayNode * _Nonnull node) {
|
||||||
node.yogaLayoutInProgress = YES;
|
node.yogaLayoutInProgress = YES;
|
||||||
[node updateYogaMeasureFuncIfNeeded];
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ASSizeRangeEqualToSizeRange(rootConstrainedSize, ASSizeRangeUnconstrained)) {
|
if (ASSizeRangeEqualToSizeRange(rootConstrainedSize, ASSizeRangeUnconstrained)) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user