From 849de89a58096c291c26c88b37400fd434ab93b2 Mon Sep 17 00:00:00 2001 From: Martin Kralik Date: Sun, 23 Apr 2017 17:14:05 -0700 Subject: [PATCH] support flexible top container Summary: The main container that gets called `applyLayoutPreservingOrigin:` is using its size as a fixed bounding box. In some cases it's preferrable to let it accomodate its contents. This diffs extends `applyLayoutPreservingOrigin:` by adding an additional parameter which can be used to sepecify whether width and/or height are fixed or flexible. Feel free to suggest better names than `YGDimensionFlexibility` & co. Let me know if you prefet to kill the API without flexiblity specifier - I'll codemod everything then. Reviewed By: dshahidehpour Differential Revision: D4929702 fbshipit-source-id: f128f244140b4a54d8ce3b3f4edddbb9756f8fdf --- YogaKit/Source/YGLayout.h | 12 +++++++++ YogaKit/Source/YGLayout.m | 14 +++++++++++ YogaKit/Tests/YogaKitTests.m | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) diff --git a/YogaKit/Source/YGLayout.h b/YogaKit/Source/YGLayout.h index 9d7768be..fd7f44c1 100644 --- a/YogaKit/Source/YGLayout.h +++ b/YogaKit/Source/YGLayout.h @@ -10,6 +10,11 @@ #import #import +typedef NS_OPTIONS(NSInteger, YGDimensionFlexibility) { + YGDimensionFlexibilityFlexibleWidth = 1 << 0, + YGDimensionFlexibilityFlexibleHeigth = 1 << 1, +}; + @interface YGLayout : NSObject /** @@ -95,6 +100,13 @@ - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin NS_SWIFT_NAME(applyLayout(preservingOrigin:)); +/** + Perform a layout calculation and update the frames of the views in the hierarchy with the results. + If the origin is not preserved, the root view's layout results will applied from {0,0}. + */ +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility + NS_SWIFT_NAME(applyLayout(preservingOrigin:dimensionFlexibility:)); + /** Returns the size of the view if no constraints were given. This could equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)]; diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index e7634b49..eddbc139 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -235,6 +235,20 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); } +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin dimensionFlexibility:(YGDimensionFlexibility)dimensionFlexibility +{ + CGSize size = self.view.bounds.size; + if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) { + size.width = YGUndefined; + } + if (dimensionFlexibility & YGDimensionFlexibilityFlexibleHeigth) { + size.height = YGUndefined; + } + [self calculateLayoutWithSize:size]; + YGApplyLayoutToViewHierarchy(self.view, NO); +} + + - (CGSize)intrinsicSize { const CGSize constrainedSize = { diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index 7fa3b0b5..583da63f 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -154,6 +154,54 @@ XCTAssertEqual(25, view2.frame.origin.y); } +- (void)testContainerWithFlexibleWidthGetsCorrectlySized +{ + UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)]; + container.yoga.isEnabled = YES; + + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + view.yoga.isEnabled = YES; + view.yoga.width = 100; + view.yoga.height = 100; + [container addSubview:view]; + + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth]; + XCTAssertEqual(100, container.frame.size.width); + XCTAssertEqual(200, container.frame.size.height); +} + +- (void)testContainerWithFlexibleHeightGetsCorrectlySized +{ + UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)]; + container.yoga.isEnabled = YES; + + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + view.yoga.isEnabled = YES; + view.yoga.width = 100; + view.yoga.height = 100; + [container addSubview:view]; + + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleHeigth]; + XCTAssertEqual(200, container.frame.size.width); + XCTAssertEqual(100, container.frame.size.height); +} + +- (void)testContainerWithFlexibleWidthAndHeightGetsCorrectlySized +{ + UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,200,200)]; + container.yoga.isEnabled = YES; + + UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; + view.yoga.isEnabled = YES; + view.yoga.width = 100; + view.yoga.height = 100; + [container addSubview:view]; + + [container.yoga applyLayoutPreservingOrigin:YES dimensionFlexibility:YGDimensionFlexibilityFlexibleWidth | YGDimensionFlexibilityFlexibleHeigth]; + XCTAssertEqual(100, container.frame.size.width); + XCTAssertEqual(100, container.frame.size.height); +} + - (void)testMarkingDirtyOnlyWorksOnLeafNodes { UIView *container = [[UIView alloc] initWithFrame:CGRectZero];