From 838ef478478b7518d8844ea8685deb42a842d330 Mon Sep 17 00:00:00 2001 From: Pavel Mazurin Date: Fri, 12 Oct 2018 14:07:33 -0700 Subject: [PATCH] Fixes #606 (#610) Summary: Fixes #606. If there are no subviews in `UIView`, yoga assumes that `sizeThatFits:` returns `CGSizeZero`. However, according to [the documentation](https://developer.apple.com/documentation/uikit/uiview/1622625-sizethatfits), `UIView` returns current size if there are no subviews. This diff adds a check - if there are no subviews, `sizeThatFits:` doesn't get called, and CGSizeZero is returned. Pull Request resolved: https://github.com/facebook/yoga/pull/610 Reviewed By: davidaurelio Differential Revision: D6807406 Pulled By: priteshrnandgaonkar fbshipit-source-id: 9189cf14c393f840122bc365d3827881bf03548c --- YogaKit/Source/YGLayout.m | 20 ++++++++++++++++---- YogaKit/Tests/YogaKitTests.m | 9 +++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index 836b34a5..7779c437 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -129,6 +129,7 @@ static YGConfigRef globalConfig; @interface YGLayout () @property (nonatomic, weak, readonly) UIView *view; +@property(nonatomic, assign, readonly) BOOL isUIView; @end @@ -153,6 +154,7 @@ static YGConfigRef globalConfig; YGNodeSetContext(_node, (__bridge void *) view); _isEnabled = NO; _isIncludedInLayout = YES; + _isUIView = [view isMemberOfClass:[UIView class]]; } return self; @@ -331,10 +333,20 @@ static YGSize YGMeasureView( const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height; UIView *view = (__bridge UIView*) YGNodeGetContext(node); - const CGSize sizeThatFits = [view sizeThatFits:(CGSize) { - .width = constrainedWidth, - .height = constrainedHeight, - }]; + CGSize sizeThatFits = CGSizeZero; + + // The default implementation of sizeThatFits: returns the existing size of + // the view. That means that if we want to layout an empty UIView, which + // already has got a frame set, its measured size should be CGSizeZero, but + // UIKit returns the existing size. + // + // See https://github.com/facebook/yoga/issues/606 for more information. + if (!view.yoga.isUIView || [view.subviews count] > 0) { + sizeThatFits = [view sizeThatFits:(CGSize){ + .width = constrainedWidth, + .height = constrainedHeight, + }]; + } return (YGSize) { .width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode), diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index 945d4d24..b9d3a6ed 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -127,6 +127,15 @@ XCTAssertEqual(longTextLabelSize.width + textBadgeView.yoga.intrinsicSize.width, containerSize.width); } +- (void)testSizeThatFitsEmptyView { + UIView* view = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 200, 200)]; + view.yoga.isEnabled = YES; + + const CGSize viewSize = view.yoga.intrinsicSize; + XCTAssertEqual(viewSize.height, 0); + XCTAssertEqual(viewSize.width, 0); +} + - (void)testPreservingOrigin { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,75)];