diff --git a/YogaKit/CHANGELOG.md b/YogaKit/CHANGELOG.md new file mode 100644 index 00000000..6a7dda86 --- /dev/null +++ b/YogaKit/CHANGELOG.md @@ -0,0 +1,23 @@ +# CHANGELOG + +The changelog for `YogaKit`. + +1.2.0 (**upcoming release**) +----- + +### Breaking Changes + +- `applyLayout()` has now been changed to `applyLayout(preservingOrigin:)`. + +- Computed properties are no longer reflected in getter's of the affected properties. +```swift +// OLD +view.yoga.margin = 10 +view.yoga.marginTop // 10 +view.yoga.marginLeft // 10 + +// NEW +view.yoga.margin = 10 +view.yoga.marginTop // 0 +view.yoga.marginLeft // 0 +``` diff --git a/YogaKit/Source/YGLayout.h b/YogaKit/Source/YGLayout.h index 83dbf36b..e9f49b12 100644 --- a/YogaKit/Source/YGLayout.h +++ b/YogaKit/Source/YGLayout.h @@ -89,9 +89,10 @@ @property (nonatomic, readonly, assign) YGDirection resolvedDirection; /** - Perform a layout calculation and update the frames of the views in the hierarchy with the results + 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)applyLayout NS_SWIFT_NAME(applyLayout()); +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin NS_SWIFT_NAME(applyLayout(preservingOrigin:)); /** Returns the size of the view if no constraints were given. This could equivalent to calling [self diff --git a/YogaKit/Source/YGLayout.m b/YogaKit/Source/YGLayout.m index 3e7516c7..07c0a77d 100644 --- a/YogaKit/Source/YGLayout.m +++ b/YogaKit/Source/YGLayout.m @@ -208,7 +208,13 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio) - (void)applyLayout { [self calculateLayoutWithSize:self.view.bounds.size]; - YGApplyLayoutToViewHierarchy(self.view, YES); + YGApplyLayoutToViewHierarchy(self.view, NO); +} + +- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin +{ + [self calculateLayoutWithSize:self.view.bounds.size]; + YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); } - (CGSize)intrinsicSize diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index 5342f9c3..dcb089e8 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -109,6 +109,31 @@ XCTAssertEqual(longTextLabelSize.width + textBadgeView.yoga.intrinsicSize.width, containerSize.width); } +- (void)testPreservingOrigin +{ + UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0,0,50,75)]; + container.yoga.isEnabled = YES; + + UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; + view.yoga.isEnabled = YES; + view.yoga.flexBasis = 0; + view.yoga.flexGrow = 1; + [container addSubview:view]; + + UIView *view2 = [[UIView alloc] initWithFrame:CGRectZero]; + view2.yoga.isEnabled = YES; + view2.yoga.marginTop = 25; + view2.yoga.flexBasis = 0; + view2.yoga.flexGrow = 1; + [container addSubview:view2]; + + [container.yoga applyLayoutPreservingOrigin:YES]; + XCTAssertEqual(50, view2.frame.origin.y); + + [view2.yoga applyLayoutPreservingOrigin:NO]; + XCTAssertEqual(25, view2.frame.origin.y); +} + - (void)testThatMarkingLeafsAsDirtyWillTriggerASizeRecalculation { UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 50)]; @@ -116,22 +141,22 @@ container.yoga.flexDirection = YGFlexDirectionRow; container.yoga.alignItems = YGAlignFlexStart; - UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; - label.text = @"This is a short text."; - label.numberOfLines = 1; - label.yoga.isEnabled = YES; - [container addSubview:label]; + UILabel *view = [[UILabel alloc] initWithFrame:CGRectZero]; + view.text = @"This is a short text."; + view.numberOfLines = 1; + view.yoga.isEnabled = YES; + [container addSubview:view]; - [container.yoga applyLayout]; - CGSize const labelSizeAfterFirstPass = label.frame.size; + [container.yoga applyLayoutPreservingOrigin:YES]; + CGSize const viewSizeAfterFirstPass = view.frame.size; - label.text = @"This is a slightly longer text."; - XCTAssertTrue(CGSizeEqualToSize(label.frame.size, labelSizeAfterFirstPass)); + view.text = @"This is a slightly longer text."; + XCTAssertTrue(CGSizeEqualToSize(view.frame.size, viewSizeAfterFirstPass)); - [label.yoga markDirty]; + [view.yoga markDirty]; - [container.yoga applyLayout]; - XCTAssertFalse(CGSizeEqualToSize(label.frame.size, labelSizeAfterFirstPass)); + [container.yoga applyLayoutPreservingOrigin:YES]; + XCTAssertFalse(CGSizeEqualToSize(view.frame.size, viewSizeAfterFirstPass)); } - (void)testFrameAndOriginPlacement @@ -157,7 +182,7 @@ subview3.yoga.flexGrow = 1; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqualWithAccuracy(subview2.frame.origin.x, CGRectGetMaxX(subview1.frame), FLT_EPSILON); XCTAssertEqualWithAccuracy(subview3.frame.origin.x, CGRectGetMaxX(subview2.frame), FLT_EPSILON); @@ -193,7 +218,7 @@ subview3.yoga.flexGrow = 1; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 100, 50))); XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50))); @@ -201,7 +226,7 @@ [container exchangeSubviewAtIndex:2 withSubviewAtIndex:0]; subview2.yoga.isIncludedInLayout = NO; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(0, 0, 150, 50))); XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(150, 0, 150, 50))); @@ -233,14 +258,14 @@ subview3.yoga.flexGrow = 1; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; for (UIView *subview in container.subviews) { XCTAssertEqual(subview.bounds.size.width, 100); } subview3.yoga.isIncludedInLayout = NO; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqual(subview1.bounds.size.width, 150); XCTAssertEqual(subview2.bounds.size.width, 150); @@ -270,11 +295,11 @@ subview3.yoga.isIncludedInLayout = YES; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqual(container.yoga.numberOfChildren, 1); subview2.yoga.isIncludedInLayout = YES; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqual(container.yoga.numberOfChildren, 2); } @@ -300,14 +325,14 @@ subview3.yoga.isIncludedInLayout = NO; [container addSubview:subview3]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqual(subview1.bounds.size.width, 150); XCTAssertEqual(subview2.bounds.size.width, 150); XCTAssertEqual(subview3.bounds.size.width, 0); subview3.yoga.isIncludedInLayout = YES; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqual(subview1.bounds.size.width, 100); XCTAssertEqual(subview2.bounds.size.width, 100); @@ -361,7 +386,7 @@ someView.yoga.flexGrow = 1; [view addSubview:someView]; } - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; // Add the same amount of new views, reapply layout. for (UIView *view in @[subview1, subview2]) { @@ -370,7 +395,7 @@ someView.yoga.flexGrow = 1; [view addSubview:someView]; } - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; XCTAssertEqual(subview1.bounds.size.width, 100); XCTAssertEqual(subview1.bounds.size.height, 25); @@ -406,9 +431,9 @@ subview2.yoga.isEnabled = YES; [subview1 addSubview:subview2]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; [subview2 removeFromSuperview]; - [container.yoga applyLayout]; + [container.yoga applyLayoutPreservingOrigin:YES]; } - (void)testPositionalPropertiesWork @@ -594,40 +619,4 @@ XCTAssertEqual(view.yoga.borderEndWidth, 7); } -- (void)testOriginIsPreservedOnRootOfLayout -{ - const CGSize containerSize = CGSizeMake(200, 50); - - UIView *container = [[UIView alloc] initWithFrame:CGRectMake(10, 10, containerSize.width, containerSize.height)]; - container.yoga.isEnabled = YES; - container.yoga.flexDirection = YGFlexDirectionRow; - - UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero]; - subview1.yoga.isEnabled = YES; - subview1.yoga.flexGrow = 1; - [container addSubview:subview1]; - - UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero]; - subview2.yoga.isEnabled = YES; - subview2.yoga.flexGrow = 1; - subview2.yoga.flexDirection = YGFlexDirectionColumn; - subview2.yoga.marginLeft = 10; - [container addSubview:subview2]; - [container.yoga applyLayout]; - - XCTAssertTrue(CGRectEqualToRect(container.frame, CGRectMake(10, 10, 200, 50))); - XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 95, 50))); - XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(105, 0, 95, 50))); - - UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero]; - subview3.yoga.isEnabled = YES; - subview3.yoga.alignSelf = YGAlignFlexEnd; - subview3.yoga.height = 50; - [subview2 addSubview:subview3]; - [subview2.yoga applyLayout]; - - XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(115, 0, 85, 50))); - XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(85,0,0,50))); -} - @end diff --git a/YogaKit/YogaKitSample/Podfile.lock b/YogaKit/YogaKitSample/Podfile.lock index f2dad1e0..031125d4 100644 --- a/YogaKit/YogaKitSample/Podfile.lock +++ b/YogaKit/YogaKitSample/Podfile.lock @@ -1,7 +1,7 @@ PODS: - - Yoga (1.0.2) - - YogaKit (1.0.3): - - Yoga (~> 1.0) + - Yoga (1.1.0) + - YogaKit (1.1.0): + - Yoga (~> 1.1) DEPENDENCIES: - YogaKit (from `../../YogaKit.podspec`) @@ -11,8 +11,8 @@ EXTERNAL SOURCES: :path: "../../YogaKit.podspec" SPEC CHECKSUMS: - Yoga: ef42f88b9bcbd7daf7267c0f19d8636ce3a50618 - YogaKit: 6d9826a015c029b13731a33bf96fe6c1e33748a6 + Yoga: 0bf083b7c485b20598020dbedcea869cbe53071e + YogaKit: 80df90de9ef2900baa111f2c93476a6f9e921385 PODFILE CHECKSUM: 9db3bdea7f1b4b715ad859a449b2dc87fb6226cc diff --git a/YogaKit/YogaKitSample/YogaKitSample/SwiftViewController.swift b/YogaKit/YogaKitSample/YogaKitSample/SwiftViewController.swift index f305a7e4..66a90199 100644 --- a/YogaKit/YogaKitSample/YogaKitSample/SwiftViewController.swift +++ b/YogaKit/YogaKitSample/YogaKitSample/SwiftViewController.swift @@ -36,6 +36,6 @@ class SwiftViewController: UIViewController { child2.addSubview(child3) root.addSubview(child1) root.addSubview(child2) - root.yoga.applyLayout() + root.yoga.applyLayout(preservingOrigin: false) } } diff --git a/YogaKit/YogaKitSample/YogaKitSample/ViewController.m b/YogaKit/YogaKitSample/YogaKitSample/ViewController.m index 4184345f..102ef144 100644 --- a/YogaKit/YogaKitSample/YogaKitSample/ViewController.m +++ b/YogaKit/YogaKitSample/YogaKitSample/ViewController.m @@ -10,10 +10,6 @@ #import -@interface ViewController () - -@end - @implementation ViewController - (void)viewDidLoad @@ -53,7 +49,7 @@ [child2 addSubview:child3]; [root addSubview:child1]; [root addSubview:child2]; - [root.yoga applyLayout]; + [root.yoga applyLayoutPreservingOrigin:NO]; } diff --git a/docs/_docs/api/yogakit.md b/docs/_docs/api/yogakit.md index 9ba7b4bf..796de28a 100644 --- a/docs/_docs/api/yogakit.md +++ b/docs/_docs/api/yogakit.md @@ -22,6 +22,6 @@ Yoga relies on `UIView` subviews to build up its internal layout tree. However, It is also possible to query the number of children **included** in layout via `numberOfChildren`. ### Layout -To apply a layout to a view (and its' subviews) you need to call `[view.yoga applyLayout]`. This will do a layout calculation (if needed) and apply the calculated frames to every view included in the layout. +To apply a layout to a view (and its' subviews) you need to call `[view.yoga applyLayoutPreservingOrigin:NO]`. This will do a layout calculation (if needed) and apply the calculated frames to every view included in the layout. In the event that you need to another layout pass on a view you can mark it dirty via `[view.yoga markDirty]`.