Improved the objective-c and swift api
Summary: Compared to what was planned, I added the `overflow` value which seemed missing. I had to modify the implementation a bit for all values which are backed by a `YGValue`, but we should probably enable the pixel dimensions in Objective-C and Swift somehow later. Closes https://github.com/facebook/yoga/pull/322 Reviewed By: dshahidehpour Differential Revision: D4386906 Pulled By: emilsjolander fbshipit-source-id: 05ac0e571ef3a8ff0be31469e449a7b23f102218
This commit is contained in:
committed by
Facebook Github Bot
parent
c169a98be6
commit
8d320ceac2
@@ -23,7 +23,7 @@
|
|||||||
XCTAssertEqual(0, YGNodeGetInstanceCount());
|
XCTAssertEqual(0, YGNodeGetInstanceCount());
|
||||||
|
|
||||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[view yg_setFlexBasis:1];
|
view.yoga.flexBasis = 1;
|
||||||
XCTAssertEqual(1, YGNodeGetInstanceCount());
|
XCTAssertEqual(1, YGNodeGetInstanceCount());
|
||||||
view = nil;
|
view = nil;
|
||||||
|
|
||||||
@@ -35,11 +35,11 @@
|
|||||||
XCTAssertEqual(0, YGNodeGetInstanceCount());
|
XCTAssertEqual(0, YGNodeGetInstanceCount());
|
||||||
|
|
||||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[view yg_setFlexBasis:1];
|
view.yoga.flexBasis = 1;
|
||||||
|
|
||||||
for (int i=0; i<10; i++) {
|
for (int i=0; i<10; i++) {
|
||||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview yg_setFlexBasis:1];
|
subview.yoga.flexBasis = 1;
|
||||||
[view addSubview:subview];
|
[view addSubview:subview];
|
||||||
}
|
}
|
||||||
XCTAssertEqual(11, YGNodeGetInstanceCount());
|
XCTAssertEqual(11, YGNodeGetInstanceCount());
|
||||||
@@ -53,69 +53,69 @@
|
|||||||
- (void)testUsesYoga
|
- (void)testUsesYoga
|
||||||
{
|
{
|
||||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
XCTAssertFalse([view yg_usesYoga]);
|
XCTAssertFalse(view.yoga.isEnabled);
|
||||||
|
|
||||||
[view yg_setUsesYoga:YES];
|
view.yoga.isEnabled = YES;
|
||||||
XCTAssertTrue([view yg_usesYoga]);
|
XCTAssertTrue(view.yoga.isEnabled);
|
||||||
|
|
||||||
[view yg_setUsesYoga:NO];
|
view.yoga.isEnabled = NO;
|
||||||
XCTAssertFalse([view yg_usesYoga]);
|
XCTAssertFalse(view.yoga.isEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testSizeThatFitsAsserts
|
- (void)testSizeThatFitsAsserts
|
||||||
{
|
{
|
||||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
dispatch_sync(dispatch_queue_create("com.facebook.Yoga.testing", DISPATCH_QUEUE_SERIAL), ^(void){
|
dispatch_sync(dispatch_queue_create("com.facebook.Yoga.testing", DISPATCH_QUEUE_SERIAL), ^(void){
|
||||||
XCTAssertThrows([view yg_intrinsicSize]);
|
XCTAssertThrows(view.yoga.intrinsicSize);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testSizeThatFitsSmoke
|
- (void)testSizeThatFitsSmoke
|
||||||
{
|
{
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
[container yg_setAlignItems:YGAlignFlexStart];
|
container.yoga.alignItems = YGAlignFlexStart;
|
||||||
|
|
||||||
UILabel *longTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
UILabel *longTextLabel = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||||
longTextLabel.text = @"This is a very very very very very very very very long piece of text.";
|
longTextLabel.text = @"This is a very very very very very very very very long piece of text.";
|
||||||
longTextLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
longTextLabel.lineBreakMode = NSLineBreakByTruncatingTail;
|
||||||
longTextLabel.numberOfLines = 1;
|
longTextLabel.numberOfLines = 1;
|
||||||
[longTextLabel yg_setUsesYoga:YES];
|
longTextLabel.yoga.isEnabled = YES;
|
||||||
[longTextLabel yg_setFlexShrink:1];
|
longTextLabel.yoga.flexShrink = 1;
|
||||||
[container addSubview:longTextLabel];
|
[container addSubview:longTextLabel];
|
||||||
|
|
||||||
UIView *textBadgeView = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *textBadgeView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[textBadgeView yg_setUsesYoga:YES];
|
textBadgeView.yoga.isEnabled = YES;
|
||||||
[textBadgeView yg_setMargin:3.0 forEdge:YGEdgeLeft];
|
textBadgeView.yoga.marginLeft = 3.0;
|
||||||
[textBadgeView yg_setWidth:10];
|
textBadgeView.yoga.width = 10;
|
||||||
[textBadgeView yg_setHeight:10];
|
textBadgeView.yoga.height = 10;
|
||||||
[container addSubview:textBadgeView];
|
[container addSubview:textBadgeView];
|
||||||
|
|
||||||
const CGSize containerSize = [container yg_intrinsicSize];
|
const CGSize containerSize = container.yoga.intrinsicSize;
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(514,21), containerSize), @"Size is actually %@", NSStringFromCGSize(containerSize));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(514,21), containerSize), @"Size is actually %@", NSStringFromCGSize(containerSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testThatMarkingLeafsAsDirtyWillTriggerASizeRecalculation
|
- (void)testThatMarkingLeafsAsDirtyWillTriggerASizeRecalculation
|
||||||
{
|
{
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 50)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 50)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
[container yg_setAlignItems:YGAlignFlexStart];
|
container.yoga.alignItems = YGAlignFlexStart;
|
||||||
|
|
||||||
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
|
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
|
||||||
label.text = @"This is a short text.";
|
label.text = @"This is a short text.";
|
||||||
label.numberOfLines = 1;
|
label.numberOfLines = 1;
|
||||||
[label yg_setUsesYoga:YES];
|
label.yoga.isEnabled = YES;
|
||||||
[container addSubview:label];
|
[container addSubview:label];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(146,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(146,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size));
|
||||||
|
|
||||||
label.text = @"This is a slightly longer text.";
|
label.text = @"This is a slightly longer text.";
|
||||||
[label yg_markDirty];
|
[label.yoga markDirty];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(213,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(213,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,17 +124,17 @@
|
|||||||
const CGSize containerSize = CGSizeMake(320, 50);
|
const CGSize containerSize = CGSizeMake(320, 50);
|
||||||
|
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview yg_setUsesYoga:YES];
|
subview.yoga.isEnabled = YES;
|
||||||
[subview yg_setFlexGrow:1];
|
subview.yoga.flexGrow = 1;
|
||||||
|
|
||||||
[container addSubview:subview];
|
[container addSubview:subview];
|
||||||
}
|
}
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:0].frame, [container.subviews objectAtIndex:1].frame));
|
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:0].frame, [container.subviews objectAtIndex:1].frame));
|
||||||
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:1].frame, [container.subviews objectAtIndex:2].frame));
|
XCTAssertFalse(CGRectIntersectsRect([container.subviews objectAtIndex:1].frame, [container.subviews objectAtIndex:2].frame));
|
||||||
@@ -153,33 +153,33 @@
|
|||||||
const CGSize containerSize = CGSizeMake(300, 50);
|
const CGSize containerSize = CGSizeMake(300, 50);
|
||||||
|
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
|
|
||||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview1 yg_setUsesYoga:YES];
|
subview1.yoga.isEnabled = YES;
|
||||||
[subview1 yg_setFlexGrow:1];
|
subview1.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview1];
|
[container addSubview:subview1];
|
||||||
|
|
||||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview2 yg_setUsesYoga:YES];
|
subview2.yoga.isEnabled = YES;
|
||||||
[subview2 yg_setFlexGrow:1];
|
subview2.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview2];
|
[container addSubview:subview2];
|
||||||
|
|
||||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview3 yg_setUsesYoga:YES];
|
subview3.yoga.isEnabled = YES;
|
||||||
[subview3 yg_setFlexGrow:1];
|
subview3.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview3];
|
[container addSubview:subview3];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 100, 50)));
|
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(0, 0, 100, 50)));
|
||||||
XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50)), @"It's actually %@", NSStringFromCGRect(subview2.frame));
|
XCTAssertTrue(CGRectEqualToRect(subview2.frame, CGRectMake(100, 0, 100, 50)), @"It's actually %@", NSStringFromCGRect(subview2.frame));
|
||||||
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(200, 0, 100, 50)));
|
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(200, 0, 100, 50)));
|
||||||
|
|
||||||
[container exchangeSubviewAtIndex:2 withSubviewAtIndex:0];
|
[container exchangeSubviewAtIndex:2 withSubviewAtIndex:0];
|
||||||
[subview2 yg_setIncludeInLayout:NO];
|
subview2.yoga.isIncludedInLayout = NO;
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(0, 0, 150, 50)));
|
XCTAssertTrue(CGRectEqualToRect(subview3.frame, CGRectMake(0, 0, 150, 50)));
|
||||||
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(150, 0, 150, 50)));
|
XCTAssertTrue(CGRectEqualToRect(subview1.frame, CGRectMake(150, 0, 150, 50)));
|
||||||
@@ -193,32 +193,32 @@
|
|||||||
const CGSize containerSize = CGSizeMake(300, 50);
|
const CGSize containerSize = CGSizeMake(300, 50);
|
||||||
|
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
|
|
||||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview1 yg_setUsesYoga:YES];
|
subview1.yoga.isEnabled = YES;
|
||||||
[subview1 yg_setFlexGrow:1];
|
subview1.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview1];
|
[container addSubview:subview1];
|
||||||
|
|
||||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview2 yg_setUsesYoga:YES];
|
subview2.yoga.isEnabled = YES;
|
||||||
[subview2 yg_setFlexGrow:1];
|
subview2.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview2];
|
[container addSubview:subview2];
|
||||||
|
|
||||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview3 yg_setUsesYoga:YES];
|
subview3.yoga.isEnabled = YES;
|
||||||
[subview3 yg_setFlexGrow:1];
|
subview3.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview3];
|
[container addSubview:subview3];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
for (UIView *view in container.subviews) {
|
for (UIView *view in container.subviews) {
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size));
|
||||||
}
|
}
|
||||||
|
|
||||||
[subview3 yg_setIncludeInLayout:NO];
|
subview3.yoga.isIncludedInLayout = NO;
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
||||||
@@ -230,62 +230,62 @@
|
|||||||
- (void)testThatNumberOfChildrenIsCorrectWhenWeIgnoreSubviews
|
- (void)testThatNumberOfChildrenIsCorrectWhenWeIgnoreSubviews
|
||||||
{
|
{
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
|
|
||||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview1 yg_setUsesYoga:YES];
|
subview1.yoga.isEnabled = YES;
|
||||||
[subview1 yg_setIncludeInLayout:NO];
|
subview1.yoga.isIncludedInLayout = NO;
|
||||||
[container addSubview:subview1];
|
[container addSubview:subview1];
|
||||||
|
|
||||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview2 yg_setUsesYoga:YES];
|
subview2.yoga.isEnabled = YES;
|
||||||
[subview2 yg_setIncludeInLayout:NO];
|
subview2.yoga.isIncludedInLayout = NO;
|
||||||
[container addSubview:subview2];
|
[container addSubview:subview2];
|
||||||
|
|
||||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview3 yg_setUsesYoga:YES];
|
subview3.yoga.isEnabled = YES;
|
||||||
[subview3 yg_setIncludeInLayout:YES];
|
subview3.yoga.isIncludedInLayout = YES;
|
||||||
[container addSubview:subview3];
|
[container addSubview:subview3];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
XCTAssertEqual(1, [container yg_numberOfChildren]);
|
XCTAssertEqual(1, container.yoga.numberOfChildren);
|
||||||
|
|
||||||
[subview2 yg_setIncludeInLayout:YES];
|
subview2.yoga.isIncludedInLayout = YES;
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
XCTAssertEqual(2, [container yg_numberOfChildren]);
|
XCTAssertEqual(2, container.yoga.numberOfChildren);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testThatViewNotIncludedInFirstLayoutPassAreIncludedInSecond
|
- (void)testThatViewNotIncludedInFirstLayoutPassAreIncludedInSecond
|
||||||
{
|
{
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionRow];
|
container.yoga.flexDirection = YGFlexDirectionRow;
|
||||||
|
|
||||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview1 yg_setUsesYoga:YES];
|
subview1.yoga.isEnabled = YES;
|
||||||
[subview1 yg_setFlexGrow:1];
|
subview1.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview1];
|
[container addSubview:subview1];
|
||||||
|
|
||||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview2 yg_setUsesYoga:YES];
|
subview2.yoga.isEnabled = YES;
|
||||||
[subview2 yg_setFlexGrow:1];
|
subview2.yoga.flexGrow = 1;
|
||||||
[container addSubview:subview2];
|
[container addSubview:subview2];
|
||||||
|
|
||||||
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview3 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview3 yg_setUsesYoga:YES];
|
subview3.yoga.isEnabled = YES;
|
||||||
[subview3 yg_setFlexGrow:1];
|
subview3.yoga.flexGrow = 1;
|
||||||
[subview3 yg_setIncludeInLayout:NO];
|
subview3.yoga.isIncludedInLayout = NO;
|
||||||
[container addSubview:subview3];
|
[container addSubview:subview3];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 50), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeZero, subview3.bounds.size), @"Actual size %@", NSStringFromCGSize(subview3.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeZero, subview3.bounds.size), @"Actual size %@", NSStringFromCGSize(subview3.bounds.size));
|
||||||
|
|
||||||
[subview3 yg_setIncludeInLayout:YES];
|
subview3.yoga.isIncludedInLayout = YES;
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
for (UIView *view in container.subviews) {
|
for (UIView *view in container.subviews) {
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 50), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(view.bounds.size));
|
||||||
}
|
}
|
||||||
@@ -294,60 +294,60 @@
|
|||||||
- (void)testyg_isLeafFlag
|
- (void)testyg_isLeafFlag
|
||||||
{
|
{
|
||||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
XCTAssertTrue(view.yg_isLeaf);
|
XCTAssertTrue(view.yoga.isLeaf);
|
||||||
|
|
||||||
for (int i=0; i<10; i++) {
|
for (int i=0; i<10; i++) {
|
||||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[view addSubview:subview];
|
[view addSubview:subview];
|
||||||
}
|
}
|
||||||
XCTAssertTrue(view.yg_isLeaf);
|
XCTAssertTrue(view.yoga.isLeaf);
|
||||||
|
|
||||||
[view yg_setUsesYoga:YES];
|
view.yoga.isEnabled = YES;
|
||||||
[view yg_setWidth:50.0];
|
view.yoga.width = 50.0;
|
||||||
XCTAssertTrue(view.yg_isLeaf);
|
XCTAssertTrue(view.yoga.isLeaf);
|
||||||
|
|
||||||
UIView *const subview = view.subviews[0];
|
UIView *const subview = view.subviews[0];
|
||||||
[subview yg_setUsesYoga:YES];
|
subview.yoga.isEnabled = YES;
|
||||||
[subview yg_setWidth:50.0];
|
subview.yoga.width = 50.0;
|
||||||
XCTAssertFalse(view.yg_isLeaf);
|
XCTAssertFalse(view.yoga.isLeaf);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)testThatWeCorrectlyAttachNestedViews
|
- (void)testThatWeCorrectlyAttachNestedViews
|
||||||
{
|
{
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
[container yg_setFlexDirection:YGFlexDirectionColumn];
|
container.yoga.flexDirection = YGFlexDirectionColumn;
|
||||||
|
|
||||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview1 yg_setUsesYoga:YES];
|
subview1.yoga.isEnabled = YES;
|
||||||
[subview1 yg_setWidth:100];
|
subview1.yoga.width = 100;
|
||||||
[subview1 yg_setFlexGrow:1];
|
subview1.yoga.flexGrow = 1;
|
||||||
[subview1 yg_setFlexDirection:YGFlexDirectionColumn];
|
subview1.yoga.flexDirection = YGFlexDirectionColumn;
|
||||||
[container addSubview:subview1];
|
[container addSubview:subview1];
|
||||||
|
|
||||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview2 yg_setUsesYoga:YES];
|
subview2.yoga.isEnabled = YES;
|
||||||
[subview2 yg_setWidth:150];
|
subview2.yoga.width = 150;
|
||||||
[subview2 yg_setFlexGrow:1];
|
subview2.yoga.flexGrow = 1;
|
||||||
[subview2 yg_setFlexDirection:YGFlexDirectionColumn];
|
subview2.yoga.flexDirection = YGFlexDirectionColumn;
|
||||||
[container addSubview:subview2];
|
[container addSubview:subview2];
|
||||||
|
|
||||||
for (UIView *view in @[subview1, subview2]) {
|
for (UIView *view in @[subview1, subview2]) {
|
||||||
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[someView yg_setUsesYoga:YES];
|
someView.yoga.isEnabled = YES;
|
||||||
[someView yg_setFlexGrow:1];
|
someView.yoga.flexGrow = 1;
|
||||||
[view addSubview:someView];
|
[view addSubview:someView];
|
||||||
}
|
}
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
// Add the same amount of new views, reapply layout.
|
// Add the same amount of new views, reapply layout.
|
||||||
for (UIView *view in @[subview1, subview2]) {
|
for (UIView *view in @[subview1, subview2]) {
|
||||||
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[someView yg_setUsesYoga:YES];
|
someView.yoga.isEnabled = YES;
|
||||||
[someView yg_setFlexGrow:1];
|
someView.yoga.flexGrow = 1;
|
||||||
[view addSubview:someView];
|
[view addSubview:someView];
|
||||||
}
|
}
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
|
|
||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 25), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 25), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
||||||
for (UIView *subview in subview1.subviews) {
|
for (UIView *subview in subview1.subviews) {
|
||||||
@@ -369,19 +369,19 @@
|
|||||||
- (void)testThatANonLeafNodeCanBecomeALeafNode
|
- (void)testThatANonLeafNodeCanBecomeALeafNode
|
||||||
{
|
{
|
||||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
||||||
[container yg_setUsesYoga:YES];
|
container.yoga.isEnabled = YES;
|
||||||
|
|
||||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview1 yg_setUsesYoga:YES];
|
subview1.yoga.isEnabled = YES;
|
||||||
[container addSubview:subview1];
|
[container addSubview:subview1];
|
||||||
|
|
||||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
[subview2 yg_setUsesYoga:YES];
|
subview2.yoga.isEnabled = YES;
|
||||||
[subview1 addSubview:subview2];
|
[subview1 addSubview:subview2];
|
||||||
|
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
[subview2 removeFromSuperview];
|
[subview2 removeFromSuperview];
|
||||||
[container yg_applyLayout];
|
[container.yoga applyLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@@ -8,76 +8,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
#import <yoga/Yoga.h>
|
#import "YGLayout.h"
|
||||||
|
|
||||||
@interface UIView (Yoga)
|
@interface UIView (Yoga)
|
||||||
|
|
||||||
/**
|
@property (nonatomic, readonly, strong) YGLayout *yoga;
|
||||||
The property that decides if we should include this view when calculating layout. Defaults to YES.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readwrite, assign, setter=yg_setIncludeInLayout:) BOOL yg_includeInLayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
The property that decides during layout/sizing whether or not yg_* properties should be applied. Defaults to NO.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, readwrite, assign, setter=yg_setUsesYoga:) BOOL yg_usesYoga;
|
|
||||||
|
|
||||||
- (void)yg_setDirection:(YGDirection)direction;
|
|
||||||
- (void)yg_setFlexDirection:(YGFlexDirection)flexDirection;
|
|
||||||
- (void)yg_setJustifyContent:(YGJustify)justifyContent;
|
|
||||||
- (void)yg_setAlignContent:(YGAlign)alignContent;
|
|
||||||
- (void)yg_setAlignItems:(YGAlign)alignItems;
|
|
||||||
- (void)yg_setAlignSelf:(YGAlign)alignSelf;
|
|
||||||
- (void)yg_setPositionType:(YGPositionType)positionType;
|
|
||||||
- (void)yg_setFlexWrap:(YGWrap)flexWrap;
|
|
||||||
- (void)yg_setOverflow:(YGOverflow)overflow;
|
|
||||||
|
|
||||||
- (void)yg_setFlexGrow:(CGFloat)flexGrow;
|
|
||||||
- (void)yg_setFlexShrink:(CGFloat)flexShrink;
|
|
||||||
- (void)yg_setFlexBasis:(CGFloat)flexBasis;
|
|
||||||
|
|
||||||
- (void)yg_setPosition:(CGFloat)position forEdge:(YGEdge)edge;
|
|
||||||
- (void)yg_setMargin:(CGFloat)margin forEdge:(YGEdge)edge;
|
|
||||||
- (void)yg_setPadding:(CGFloat)padding forEdge:(YGEdge)edge;
|
|
||||||
|
|
||||||
- (void)yg_setWidth:(CGFloat)width;
|
|
||||||
- (void)yg_setHeight:(CGFloat)height;
|
|
||||||
- (void)yg_setMinWidth:(CGFloat)minWidth;
|
|
||||||
- (void)yg_setMinHeight:(CGFloat)minHeight;
|
|
||||||
- (void)yg_setMaxWidth:(CGFloat)maxWidth;
|
|
||||||
- (void)yg_setMaxHeight:(CGFloat)maxHeight;
|
|
||||||
|
|
||||||
// Yoga specific properties, not compatible with flexbox specification
|
|
||||||
- (void)yg_setAspectRatio:(CGFloat)aspectRatio;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get the resolved direction of this node. This won't be YGDirectionInherit
|
|
||||||
*/
|
|
||||||
- (YGDirection)yg_resolvedDirection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Perform a layout calculation and update the frames of the views in the hierarchy with the results
|
|
||||||
*/
|
|
||||||
- (void)yg_applyLayout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the size of the view if no constraints were given. This could equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
|
|
||||||
*/
|
|
||||||
- (CGSize)yg_intrinsicSize;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Returns the number of children that are using Flexbox.
|
|
||||||
*/
|
|
||||||
- (NSUInteger)yg_numberOfChildren;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Return a BOOL indiciating whether or not we this node contains any subviews that are included in Yoga's layout.
|
|
||||||
*/
|
|
||||||
- (BOOL)yg_isLeaf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Mark that a view's layout needs to be recalculated. Only works for leaf views.
|
|
||||||
*/
|
|
||||||
- (void)yg_markDirty;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@@ -8,404 +8,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "UIView+Yoga.h"
|
#import "UIView+Yoga.h"
|
||||||
|
#import "YGLayout+Private.h"
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
static const void *kYGNodeBridgeAssociatedKey = &kYGNodeBridgeAssociatedKey;
|
static const void *kYGYogaAssociatedKey = &kYGYogaAssociatedKey;
|
||||||
|
|
||||||
@interface YGNodeBridge : NSObject
|
@implementation UIView (YogaKit)
|
||||||
@property (nonatomic, assign, readonly) YGNodeRef cnode;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation YGNodeBridge
|
- (YGLayout *)yoga
|
||||||
|
|
||||||
+ (void)initialize
|
|
||||||
{
|
{
|
||||||
YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true);
|
YGLayout *yoga = objc_getAssociatedObject(self, kYGYogaAssociatedKey);
|
||||||
}
|
if (!yoga) {
|
||||||
|
yoga = [[YGLayout alloc] initWithView:self];
|
||||||
- (instancetype)init
|
objc_setAssociatedObject(self, kYGYogaAssociatedKey, yoga, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||||
{
|
|
||||||
if ([super init]) {
|
|
||||||
_cnode = YGNodeNew();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return yoga;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc
|
|
||||||
{
|
|
||||||
YGNodeFree(_cnode);
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation UIView (Yoga)
|
|
||||||
|
|
||||||
- (void)yg_markDirty
|
|
||||||
{
|
|
||||||
YGNodeBridge *const bridge = objc_getAssociatedObject(self, kYGNodeBridgeAssociatedKey);
|
|
||||||
if (bridge != nil && [self yg_isLeaf]) {
|
|
||||||
YGNodeMarkDirty(bridge.cnode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)yg_usesYoga
|
|
||||||
{
|
|
||||||
NSNumber *usesYoga = objc_getAssociatedObject(self, @selector(yg_usesYoga));
|
|
||||||
return [usesYoga boolValue];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)yg_includeInLayout
|
|
||||||
{
|
|
||||||
NSNumber *includeInLayout = objc_getAssociatedObject(self, @selector(yg_includeInLayout));
|
|
||||||
return (includeInLayout != nil) ? [includeInLayout boolValue] : YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSUInteger)yg_numberOfChildren
|
|
||||||
{
|
|
||||||
return YGNodeGetChildCount([self ygNode]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)yg_isLeaf
|
|
||||||
{
|
|
||||||
NSAssert([NSThread isMainThread], @"This method must be called on the main thread.");
|
|
||||||
if ([self yg_usesYoga]) {
|
|
||||||
for (UIView *subview in self.subviews) {
|
|
||||||
if ([subview yg_usesYoga] && [subview yg_includeInLayout]) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Setters
|
|
||||||
|
|
||||||
- (void)yg_setIncludeInLayout:(BOOL)includeInLayout
|
|
||||||
{
|
|
||||||
objc_setAssociatedObject(
|
|
||||||
self,
|
|
||||||
@selector(yg_includeInLayout),
|
|
||||||
@(includeInLayout),
|
|
||||||
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setUsesYoga:(BOOL)enabled
|
|
||||||
{
|
|
||||||
objc_setAssociatedObject(
|
|
||||||
self,
|
|
||||||
@selector(yg_usesYoga),
|
|
||||||
@(enabled),
|
|
||||||
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setDirection:(YGDirection)direction
|
|
||||||
{
|
|
||||||
YGNodeStyleSetDirection([self ygNode], direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setFlexDirection:(YGFlexDirection)flexDirection
|
|
||||||
{
|
|
||||||
YGNodeStyleSetFlexDirection([self ygNode], flexDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setJustifyContent:(YGJustify)justifyContent
|
|
||||||
{
|
|
||||||
YGNodeStyleSetJustifyContent([self ygNode], justifyContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setAlignContent:(YGAlign)alignContent
|
|
||||||
{
|
|
||||||
YGNodeStyleSetAlignContent([self ygNode], alignContent);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setAlignItems:(YGAlign)alignItems
|
|
||||||
{
|
|
||||||
YGNodeStyleSetAlignItems([self ygNode], alignItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setAlignSelf:(YGAlign)alignSelf
|
|
||||||
{
|
|
||||||
YGNodeStyleSetAlignSelf([self ygNode], alignSelf);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setPositionType:(YGPositionType)positionType
|
|
||||||
{
|
|
||||||
YGNodeStyleSetPositionType([self ygNode], positionType);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setFlexWrap:(YGWrap)flexWrap
|
|
||||||
{
|
|
||||||
YGNodeStyleSetFlexWrap([self ygNode], flexWrap);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setOverflow:(YGOverflow)overflow
|
|
||||||
{
|
|
||||||
YGNodeStyleSetOverflow([self ygNode], overflow);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setFlexGrow:(CGFloat)flexGrow
|
|
||||||
{
|
|
||||||
YGNodeStyleSetFlexGrow([self ygNode], flexGrow);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setFlexShrink:(CGFloat)flexShrink
|
|
||||||
{
|
|
||||||
YGNodeStyleSetFlexShrink([self ygNode], flexShrink);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setFlexBasis:(CGFloat)flexBasis
|
|
||||||
{
|
|
||||||
YGNodeStyleSetFlexBasis([self ygNode], flexBasis);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setPosition:(CGFloat)position forEdge:(YGEdge)edge
|
|
||||||
{
|
|
||||||
YGNodeStyleSetPosition([self ygNode], edge, position);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setMargin:(CGFloat)margin forEdge:(YGEdge)edge
|
|
||||||
{
|
|
||||||
YGNodeStyleSetMargin([self ygNode], edge, margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setPadding:(CGFloat)padding forEdge:(YGEdge)edge
|
|
||||||
{
|
|
||||||
YGNodeStyleSetPadding([self ygNode], edge, padding);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setWidth:(CGFloat)width
|
|
||||||
{
|
|
||||||
YGNodeStyleSetWidth([self ygNode], width);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setHeight:(CGFloat)height
|
|
||||||
{
|
|
||||||
YGNodeStyleSetHeight([self ygNode], height);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setMinWidth:(CGFloat)minWidth
|
|
||||||
{
|
|
||||||
YGNodeStyleSetMinWidth([self ygNode], minWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setMinHeight:(CGFloat)minHeight
|
|
||||||
{
|
|
||||||
YGNodeStyleSetMinHeight([self ygNode], minHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setMaxWidth:(CGFloat)maxWidth
|
|
||||||
{
|
|
||||||
YGNodeStyleSetMaxWidth([self ygNode], maxWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setMaxHeight:(CGFloat)maxHeight
|
|
||||||
{
|
|
||||||
YGNodeStyleSetMaxHeight([self ygNode], maxHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_setAspectRatio:(CGFloat)aspectRatio
|
|
||||||
{
|
|
||||||
YGNodeStyleSetAspectRatio([self ygNode], aspectRatio);
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Layout and Sizing
|
|
||||||
|
|
||||||
- (YGDirection)yg_resolvedDirection
|
|
||||||
{
|
|
||||||
return YGNodeLayoutGetDirection([self ygNode]);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)yg_applyLayout
|
|
||||||
{
|
|
||||||
[self calculateLayoutWithSize:self.bounds.size];
|
|
||||||
YGApplyLayoutToViewHierarchy(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGSize)yg_intrinsicSize
|
|
||||||
{
|
|
||||||
const CGSize constrainedSize = {
|
|
||||||
.width = YGUndefined,
|
|
||||||
.height = YGUndefined,
|
|
||||||
};
|
|
||||||
return [self calculateLayoutWithSize:constrainedSize];
|
|
||||||
}
|
|
||||||
|
|
||||||
#pragma mark - Private
|
|
||||||
|
|
||||||
- (YGNodeRef)ygNode
|
|
||||||
{
|
|
||||||
YGNodeBridge *node = objc_getAssociatedObject(self, kYGNodeBridgeAssociatedKey);
|
|
||||||
if (!node) {
|
|
||||||
node = [YGNodeBridge new];
|
|
||||||
YGNodeSetContext(node.cnode, (__bridge void *) self);
|
|
||||||
objc_setAssociatedObject(self, kYGNodeBridgeAssociatedKey, node, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
|
||||||
}
|
|
||||||
return node.cnode;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (CGSize)calculateLayoutWithSize:(CGSize)size
|
|
||||||
{
|
|
||||||
NSAssert([NSThread isMainThread], @"YG Layout calculation must be done on main.");
|
|
||||||
NSAssert([self yg_usesYoga], @"YG Layout is not enabled for this view.");
|
|
||||||
|
|
||||||
YGAttachNodesFromViewHierachy(self);
|
|
||||||
|
|
||||||
const YGNodeRef node = [self ygNode];
|
|
||||||
YGNodeCalculateLayout(
|
|
||||||
node,
|
|
||||||
size.width,
|
|
||||||
size.height,
|
|
||||||
YGNodeStyleGetDirection(node));
|
|
||||||
|
|
||||||
return (CGSize) {
|
|
||||||
.width = YGNodeLayoutGetWidth(node),
|
|
||||||
.height = YGNodeLayoutGetHeight(node),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static YGSize YGMeasureView(
|
|
||||||
YGNodeRef node,
|
|
||||||
float width,
|
|
||||||
YGMeasureMode widthMode,
|
|
||||||
float height,
|
|
||||||
YGMeasureMode heightMode)
|
|
||||||
{
|
|
||||||
const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width;
|
|
||||||
const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height;
|
|
||||||
|
|
||||||
UIView *view = (__bridge UIView*) YGNodeGetContext(node);
|
|
||||||
const CGSize sizeThatFits = [view sizeThatFits:(CGSize) {
|
|
||||||
.width = constrainedWidth,
|
|
||||||
.height = constrainedHeight,
|
|
||||||
}];
|
|
||||||
|
|
||||||
return (YGSize) {
|
|
||||||
.width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
|
|
||||||
.height = YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static CGFloat YGSanitizeMeasurement(
|
|
||||||
CGFloat constrainedSize,
|
|
||||||
CGFloat measuredSize,
|
|
||||||
YGMeasureMode measureMode)
|
|
||||||
{
|
|
||||||
CGFloat result;
|
|
||||||
if (measureMode == YGMeasureModeExactly) {
|
|
||||||
result = constrainedSize;
|
|
||||||
} else if (measureMode == YGMeasureModeAtMost) {
|
|
||||||
result = MIN(constrainedSize, measuredSize);
|
|
||||||
} else {
|
|
||||||
result = measuredSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray<UIView *> *subviews)
|
|
||||||
{
|
|
||||||
if (YGNodeGetChildCount(node) != subviews.count) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<subviews.count; i++) {
|
|
||||||
if (YGNodeGetChild(node, i) != subviews[i].ygNode) {
|
|
||||||
return NO;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void YGAttachNodesFromViewHierachy(UIView *const view)
|
|
||||||
{
|
|
||||||
const YGNodeRef node = [view ygNode];
|
|
||||||
|
|
||||||
// Only leaf nodes should have a measure function
|
|
||||||
if (view.yg_isLeaf) {
|
|
||||||
YGRemoveAllChildren(node);
|
|
||||||
YGNodeSetMeasureFunc(node, YGMeasureView);
|
|
||||||
} else {
|
|
||||||
YGNodeSetMeasureFunc(node, NULL);
|
|
||||||
|
|
||||||
NSMutableArray<UIView *> *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count];
|
|
||||||
for (UIView *subview in view.subviews) {
|
|
||||||
if ([subview yg_includeInLayout]) {
|
|
||||||
[subviewsToInclude addObject:subview];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) {
|
|
||||||
YGRemoveAllChildren(node);
|
|
||||||
for (int i=0; i<subviewsToInclude.count; i++) {
|
|
||||||
YGNodeInsertChild(node, [subviewsToInclude[i] ygNode], i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (UIView *const subview in subviewsToInclude) {
|
|
||||||
YGAttachNodesFromViewHierachy(subview);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void YGRemoveAllChildren(const YGNodeRef node)
|
|
||||||
{
|
|
||||||
if (node == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (YGNodeGetChildCount(node) > 0) {
|
|
||||||
YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static CGFloat YGRoundPixelValue(CGFloat value)
|
|
||||||
{
|
|
||||||
static CGFloat scale;
|
|
||||||
static dispatch_once_t onceToken;
|
|
||||||
dispatch_once(&onceToken, ^(){
|
|
||||||
scale = [UIScreen mainScreen].scale;
|
|
||||||
});
|
|
||||||
|
|
||||||
return round(value * scale) / scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void YGApplyLayoutToViewHierarchy(UIView *view)
|
|
||||||
{
|
|
||||||
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
|
|
||||||
if (![view yg_includeInLayout]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
YGNodeRef node = [view ygNode];
|
|
||||||
const CGPoint topLeft = {
|
|
||||||
YGNodeLayoutGetLeft(node),
|
|
||||||
YGNodeLayoutGetTop(node),
|
|
||||||
};
|
|
||||||
|
|
||||||
const CGPoint bottomRight = {
|
|
||||||
topLeft.x + YGNodeLayoutGetWidth(node),
|
|
||||||
topLeft.y + YGNodeLayoutGetHeight(node),
|
|
||||||
};
|
|
||||||
|
|
||||||
view.frame = (CGRect) {
|
|
||||||
.origin = {
|
|
||||||
.x = YGRoundPixelValue(topLeft.x),
|
|
||||||
.y = YGRoundPixelValue(topLeft.y),
|
|
||||||
},
|
|
||||||
.size = {
|
|
||||||
.width = YGRoundPixelValue(bottomRight.x) - YGRoundPixelValue(topLeft.x),
|
|
||||||
.height = YGRoundPixelValue(bottomRight.y) - YGRoundPixelValue(topLeft.y),
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!view.yg_isLeaf) {
|
|
||||||
for (NSUInteger i=0; i<view.subviews.count; i++) {
|
|
||||||
YGApplyLayoutToViewHierarchy(view.subviews[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
16
YogaKit/YGLayout+Private.h
Normal file
16
YogaKit/YGLayout+Private.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "YGLayout.h"
|
||||||
|
|
||||||
|
@interface YGLayout (Private)
|
||||||
|
|
||||||
|
- (instancetype)initWithView:(UIView *)view;
|
||||||
|
|
||||||
|
@end
|
114
YogaKit/YGLayout.h
Normal file
114
YogaKit/YGLayout.h
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
#import <yoga/YGEnums.h>
|
||||||
|
|
||||||
|
@interface YGLayout : NSObject
|
||||||
|
|
||||||
|
/**
|
||||||
|
The property that decides if we should include this view when calculating layout. Defaults to YES.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readwrite, assign, setter=setIncludedInLayout:) BOOL isIncludedInLayout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
The property that decides during layout/sizing whether or not styling properties should be applied. Defaults to NO.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readwrite, assign, setter=setEnabled:) BOOL isEnabled;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) YGDirection direction;
|
||||||
|
@property (nonatomic, readwrite, assign) YGFlexDirection flexDirection;
|
||||||
|
@property (nonatomic, readwrite, assign) YGJustify justifyContent;
|
||||||
|
@property (nonatomic, readwrite, assign) YGAlign alignContent;
|
||||||
|
@property (nonatomic, readwrite, assign) YGAlign alignItems;
|
||||||
|
@property (nonatomic, readwrite, assign) YGAlign alignSelf;
|
||||||
|
@property (nonatomic, readwrite, assign) YGPositionType position;
|
||||||
|
@property (nonatomic, readwrite, assign) YGWrap flexWrap;
|
||||||
|
@property (nonatomic, readwrite, assign) YGOverflow overflow;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat flexGrow;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat flexShrink;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat flexBasis;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat left;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat top;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat right;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat bottom;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat start;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat end;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginLeft;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginTop;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginRight;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginBottom;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginStart;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginEnd;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginHorizontal;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat marginVertical;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat margin;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingLeft;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingTop;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingRight;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingBottom;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingStart;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingEnd;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingHorizontal;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat paddingVertical;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat padding;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderLeftWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderTopWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderRightWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderBottomWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderStartWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderEndWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat borderWidth;
|
||||||
|
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat width;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat height;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat minWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat minHeight;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat maxWidth;
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat maxHeight;
|
||||||
|
|
||||||
|
// Yoga specific properties, not compatible with flexbox specification
|
||||||
|
@property (nonatomic, readwrite, assign) CGFloat aspectRatio;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get the resolved direction of this node. This won't be YGDirectionInherit
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly, assign) YGDirection resolvedDirection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Perform a layout calculation and update the frames of the views in the hierarchy with the results
|
||||||
|
*/
|
||||||
|
- (void)applyLayout NS_SWIFT_NAME(applyLayout());
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the size of the view if no constraints were given. This could equivalent to calling [self sizeThatFits:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly, assign) CGSize intrinsicSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the number of children that are using Flexbox.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly, assign) NSUInteger numberOfChildren;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return a BOOL indiciating whether or not we this node contains any subviews that are included in Yoga's layout.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readonly, assign) BOOL isLeaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Mark that a view's layout needs to be recalculated. Only works for leaf views.
|
||||||
|
*/
|
||||||
|
- (void)markDirty;
|
||||||
|
|
||||||
|
@end
|
380
YogaKit/YGLayout.m
Normal file
380
YogaKit/YGLayout.m
Normal file
@@ -0,0 +1,380 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "YGLayout+Private.h"
|
||||||
|
#import "UIView+Yoga.h"
|
||||||
|
#import <yoga/Yoga.h>
|
||||||
|
|
||||||
|
#define YG_STYLE_PROPERTY_IMPL(type, lowercased_name, capitalized_name) \
|
||||||
|
- (type)lowercased_name \
|
||||||
|
{ \
|
||||||
|
return YGNodeStyleGet##capitalized_name(self.node); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
- (void)set##capitalized_name:(type)lowercased_name \
|
||||||
|
{ \
|
||||||
|
YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define YG_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, property, edge) \
|
||||||
|
- (CGFloat)lowercased_name { \
|
||||||
|
return YGNodeStyleGet##property(self.node, edge); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
- (void)set##capitalized_name:(CGFloat)lowercased_name { \
|
||||||
|
YGNodeStyleSet##property(self.node, edge, lowercased_name); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define YG_STYLE_VALUE_PROPERTY_IMPL(lowercased_name, capitalized_name) \
|
||||||
|
- (CGFloat)lowercased_name \
|
||||||
|
{ \
|
||||||
|
YGValue value = YGNodeStyleGet##capitalized_name(self.node); \
|
||||||
|
if (value.unit == YGUnitPixel) { \
|
||||||
|
return value.value; \
|
||||||
|
} else { \
|
||||||
|
return YGUndefined; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
- (void)set##capitalized_name:(CGFloat)lowercased_name \
|
||||||
|
{ \
|
||||||
|
YGNodeStyleSet##capitalized_name(self.node, lowercased_name); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, edge, edge_suffix) \
|
||||||
|
- (CGFloat)lowercased_name##edge_suffix \
|
||||||
|
{ \
|
||||||
|
YGValue value = YGNodeStyleGet##capitalized_name(self.node, edge); \
|
||||||
|
if (value.unit == YGUnitPixel) { \
|
||||||
|
return value.value; \
|
||||||
|
} else { \
|
||||||
|
return YGUndefined; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
- (void)set##capitalized_name##edge_suffix:(CGFloat)lowercased_name \
|
||||||
|
{ \
|
||||||
|
YGNodeStyleSet##capitalized_name(self.node, edge, lowercased_name); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define YG_STYLE_ALL_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeLeft, Left) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeTop, Top) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeRight, Right) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeBottom, Bottom) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeStart, Start) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeEnd, End) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeHorizontal, Horizontal) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeVertical, Vertical) \
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(lowercased_name, capitalized_name, YGEdgeAll, )
|
||||||
|
|
||||||
|
@interface YGLayout ()
|
||||||
|
|
||||||
|
@property (nonatomic, weak, readonly) UIView *view;
|
||||||
|
@property (nonatomic, assign, readonly) YGNodeRef node;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation YGLayout
|
||||||
|
|
||||||
|
@synthesize isEnabled=_isEnabled;
|
||||||
|
@synthesize isIncludedInLayout=_isIncludedInLayout;
|
||||||
|
|
||||||
|
+ (void)initialize
|
||||||
|
{
|
||||||
|
YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (instancetype)initWithView:(UIView*)view
|
||||||
|
{
|
||||||
|
if (self = [super init]) {
|
||||||
|
_view = view;
|
||||||
|
_node = YGNodeNew();
|
||||||
|
YGNodeSetContext(_node, (__bridge void *) view);
|
||||||
|
_isEnabled = NO;
|
||||||
|
_isIncludedInLayout = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
YGNodeFree(self.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)markDirty
|
||||||
|
{
|
||||||
|
if (self.isLeaf) {
|
||||||
|
YGNodeMarkDirty(self.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)numberOfChildren
|
||||||
|
{
|
||||||
|
return YGNodeGetChildCount(self.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)isLeaf
|
||||||
|
{
|
||||||
|
NSAssert([NSThread isMainThread], @"This method must be called on the main thread.");
|
||||||
|
if (self.isEnabled) {
|
||||||
|
for (UIView *subview in self.view.subviews) {
|
||||||
|
YGLayout *const yoga = subview.yoga;
|
||||||
|
if (yoga.isEnabled && yoga.isIncludedInLayout) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Style
|
||||||
|
|
||||||
|
- (YGPositionType)position
|
||||||
|
{
|
||||||
|
return YGNodeStyleGetPositionType(self.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setPosition:(YGPositionType)position
|
||||||
|
{
|
||||||
|
YGNodeStyleSetPositionType(self.node, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGDirection, direction, Direction)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGFlexDirection, flexDirection, FlexDirection)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGJustify, justifyContent, JustifyContent)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGAlign, alignContent, AlignContent)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGAlign, alignItems, AlignItems)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGAlign, alignSelf, AlignSelf)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGWrap, flexWrap, FlexWrap)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(YGOverflow, overflow, Overflow)
|
||||||
|
|
||||||
|
YG_STYLE_PROPERTY_IMPL(CGFloat, flexGrow, FlexGrow)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(CGFloat, flexShrink, FlexShrink)
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(flexBasis, FlexBasis)
|
||||||
|
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeLeft, Left)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeTop, Top)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeRight, Right)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeBottom, Bottom)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeStart, Start)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_UNIT_IMPL(position, Position, YGEdgeEnd, End)
|
||||||
|
YG_STYLE_ALL_EDGE_PROPERTY_UNIT_IMPL(margin, Margin)
|
||||||
|
YG_STYLE_ALL_EDGE_PROPERTY_UNIT_IMPL(padding, Padding)
|
||||||
|
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderLeftWidth, BorderLeftWidth, Border, YGEdgeLeft)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderTopWidth, BorderTopWidth, Border, YGEdgeTop)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderRightWidth, BorderRightWidth, Border, YGEdgeRight)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderBottomWidth, BorderBottomWidth, Border, YGEdgeBottom)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderStartWidth, BorderStartWidth, Border, YGEdgeStart)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderEndWidth, BorderEndWidth, Border, YGEdgeEnd)
|
||||||
|
YG_STYLE_EDGE_PROPERTY_IMPL(borderWidth, BorderWidth, Border, YGEdgeAll)
|
||||||
|
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(width, Width)
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(height, Height)
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(minWidth, MinWidth)
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(minHeight, MinHeight)
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(maxWidth, MaxWidth)
|
||||||
|
YG_STYLE_VALUE_PROPERTY_IMPL(maxHeight, MaxHeight)
|
||||||
|
YG_STYLE_PROPERTY_IMPL(CGFloat, aspectRatio, AspectRatio)
|
||||||
|
|
||||||
|
#pragma mark - Layout and Sizing
|
||||||
|
|
||||||
|
- (YGDirection)resolvedDirection
|
||||||
|
{
|
||||||
|
return YGNodeLayoutGetDirection(self.node);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applyLayout
|
||||||
|
{
|
||||||
|
[self calculateLayoutWithSize:self.view.bounds.size];
|
||||||
|
YGApplyLayoutToViewHierarchy(self.view);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CGSize)intrinsicSize
|
||||||
|
{
|
||||||
|
const CGSize constrainedSize = {
|
||||||
|
.width = YGUndefined,
|
||||||
|
.height = YGUndefined,
|
||||||
|
};
|
||||||
|
return [self calculateLayoutWithSize:constrainedSize];
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (CGSize)calculateLayoutWithSize:(CGSize)size
|
||||||
|
{
|
||||||
|
NSAssert([NSThread isMainThread], @"Yoga calculation must be done on main.");
|
||||||
|
NSAssert(self.isEnabled, @"Yoga is not enabled for this view.");
|
||||||
|
|
||||||
|
YGAttachNodesFromViewHierachy(self.view);
|
||||||
|
|
||||||
|
const YGNodeRef node = self.node;
|
||||||
|
YGNodeCalculateLayout(
|
||||||
|
node,
|
||||||
|
size.width,
|
||||||
|
size.height,
|
||||||
|
YGNodeStyleGetDirection(node));
|
||||||
|
|
||||||
|
return (CGSize) {
|
||||||
|
.width = YGNodeLayoutGetWidth(node),
|
||||||
|
.height = YGNodeLayoutGetHeight(node),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static YGSize YGMeasureView(
|
||||||
|
YGNodeRef node,
|
||||||
|
float width,
|
||||||
|
YGMeasureMode widthMode,
|
||||||
|
float height,
|
||||||
|
YGMeasureMode heightMode)
|
||||||
|
{
|
||||||
|
const CGFloat constrainedWidth = (widthMode == YGMeasureModeUndefined) ? CGFLOAT_MAX : width;
|
||||||
|
const CGFloat constrainedHeight = (heightMode == YGMeasureModeUndefined) ? CGFLOAT_MAX: height;
|
||||||
|
|
||||||
|
UIView *view = (__bridge UIView*) YGNodeGetContext(node);
|
||||||
|
const CGSize sizeThatFits = [view sizeThatFits:(CGSize) {
|
||||||
|
.width = constrainedWidth,
|
||||||
|
.height = constrainedHeight,
|
||||||
|
}];
|
||||||
|
|
||||||
|
return (YGSize) {
|
||||||
|
.width = YGSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
|
||||||
|
.height = YGSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static CGFloat YGSanitizeMeasurement(
|
||||||
|
CGFloat constrainedSize,
|
||||||
|
CGFloat measuredSize,
|
||||||
|
YGMeasureMode measureMode)
|
||||||
|
{
|
||||||
|
CGFloat result;
|
||||||
|
if (measureMode == YGMeasureModeExactly) {
|
||||||
|
result = constrainedSize;
|
||||||
|
} else if (measureMode == YGMeasureModeAtMost) {
|
||||||
|
result = MIN(constrainedSize, measuredSize);
|
||||||
|
} else {
|
||||||
|
result = measuredSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static BOOL YGNodeHasExactSameChildren(const YGNodeRef node, NSArray<UIView *> *subviews)
|
||||||
|
{
|
||||||
|
if (YGNodeGetChildCount(node) != subviews.count) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<subviews.count; i++) {
|
||||||
|
if (YGNodeGetChild(node, i) != subviews[i].yoga.node) {
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void YGAttachNodesFromViewHierachy(UIView *const view)
|
||||||
|
{
|
||||||
|
YGLayout *const yoga = view.yoga;
|
||||||
|
const YGNodeRef node = yoga.node;
|
||||||
|
|
||||||
|
// Only leaf nodes should have a measure function
|
||||||
|
if (yoga.isLeaf) {
|
||||||
|
YGRemoveAllChildren(node);
|
||||||
|
YGNodeSetMeasureFunc(node, YGMeasureView);
|
||||||
|
} else {
|
||||||
|
YGNodeSetMeasureFunc(node, NULL);
|
||||||
|
|
||||||
|
NSMutableArray<UIView *> *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count];
|
||||||
|
for (UIView *subview in view.subviews) {
|
||||||
|
if (subview.yoga.isIncludedInLayout) {
|
||||||
|
[subviewsToInclude addObject:subview];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) {
|
||||||
|
YGRemoveAllChildren(node);
|
||||||
|
for (int i=0; i<subviewsToInclude.count; i++) {
|
||||||
|
YGNodeInsertChild(node, subviewsToInclude[i].yoga.node, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UIView *const subview in subviewsToInclude) {
|
||||||
|
YGAttachNodesFromViewHierachy(subview);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void YGRemoveAllChildren(const YGNodeRef node)
|
||||||
|
{
|
||||||
|
if (node == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (YGNodeGetChildCount(node) > 0) {
|
||||||
|
YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static CGFloat YGRoundPixelValue(CGFloat value)
|
||||||
|
{
|
||||||
|
static CGFloat scale;
|
||||||
|
static dispatch_once_t onceToken;
|
||||||
|
dispatch_once(&onceToken, ^(){
|
||||||
|
scale = [UIScreen mainScreen].scale;
|
||||||
|
});
|
||||||
|
|
||||||
|
return round(value * scale) / scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void YGApplyLayoutToViewHierarchy(UIView *view)
|
||||||
|
{
|
||||||
|
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
|
||||||
|
|
||||||
|
const YGLayout *yoga = view.yoga;
|
||||||
|
|
||||||
|
if (!yoga.isIncludedInLayout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
YGNodeRef node = yoga.node;
|
||||||
|
const CGPoint topLeft = {
|
||||||
|
YGNodeLayoutGetLeft(node),
|
||||||
|
YGNodeLayoutGetTop(node),
|
||||||
|
};
|
||||||
|
|
||||||
|
const CGPoint bottomRight = {
|
||||||
|
topLeft.x + YGNodeLayoutGetWidth(node),
|
||||||
|
topLeft.y + YGNodeLayoutGetHeight(node),
|
||||||
|
};
|
||||||
|
|
||||||
|
view.frame = (CGRect) {
|
||||||
|
.origin = {
|
||||||
|
.x = YGRoundPixelValue(topLeft.x),
|
||||||
|
.y = YGRoundPixelValue(topLeft.y),
|
||||||
|
},
|
||||||
|
.size = {
|
||||||
|
.width = YGRoundPixelValue(bottomRight.x) - YGRoundPixelValue(topLeft.x),
|
||||||
|
.height = YGRoundPixelValue(bottomRight.y) - YGRoundPixelValue(topLeft.y),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!yoga.isLeaf) {
|
||||||
|
for (NSUInteger i=0; i<view.subviews.count; i++) {
|
||||||
|
YGApplyLayoutToViewHierarchy(view.subviews[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
@@ -20,6 +20,9 @@
|
|||||||
13687D821DF87CF200E7C260 /* Yoga.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D621DF8778F00E7C260 /* Yoga.c */; };
|
13687D821DF87CF200E7C260 /* Yoga.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D621DF8778F00E7C260 /* Yoga.c */; };
|
||||||
13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D841DF87D1E00E7C260 /* UIKit.framework */; };
|
13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D841DF87D1E00E7C260 /* UIKit.framework */; };
|
||||||
13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D861DF87D2400E7C260 /* Foundation.framework */; };
|
13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D861DF87D2400E7C260 /* Foundation.framework */; };
|
||||||
|
638A94431E1EF5D000A726AD /* YGLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 638A94411E1EF5D000A726AD /* YGLayout.m */; };
|
||||||
|
638A94451E1EF8A900A726AD /* YGValue.h in yoga */ = {isa = PBXBuildFile; fileRef = 638A94441E1EF89C00A726AD /* YGValue.h */; };
|
||||||
|
638A94481E1F06D100A726AD /* SwiftViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 638A94471E1F06D100A726AD /* SwiftViewController.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXCopyFilesBuildPhase section */
|
/* Begin PBXCopyFilesBuildPhase section */
|
||||||
@@ -29,6 +32,7 @@
|
|||||||
dstPath = include/yoga;
|
dstPath = include/yoga;
|
||||||
dstSubfolderSpec = 16;
|
dstSubfolderSpec = 16;
|
||||||
files = (
|
files = (
|
||||||
|
638A94451E1EF8A900A726AD /* YGValue.h in yoga */,
|
||||||
13687D781DF878C600E7C260 /* YGEnums.h in yoga */,
|
13687D781DF878C600E7C260 /* YGEnums.h in yoga */,
|
||||||
13687D791DF878C600E7C260 /* YGMacros.h in yoga */,
|
13687D791DF878C600E7C260 /* YGMacros.h in yoga */,
|
||||||
13687D7A1DF878C600E7C260 /* Yoga.h in yoga */,
|
13687D7A1DF878C600E7C260 /* Yoga.h in yoga */,
|
||||||
@@ -68,6 +72,12 @@
|
|||||||
13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+Yoga.m"; sourceTree = "<group>"; };
|
13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+Yoga.m"; sourceTree = "<group>"; };
|
||||||
13687D841DF87D1E00E7C260 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
13687D841DF87D1E00E7C260 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
|
||||||
13687D861DF87D2400E7C260 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
13687D861DF87D2400E7C260 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||||
|
638A94401E1EF5D000A726AD /* YGLayout.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGLayout.h; sourceTree = "<group>"; };
|
||||||
|
638A94411E1EF5D000A726AD /* YGLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YGLayout.m; sourceTree = "<group>"; };
|
||||||
|
638A94421E1EF5D000A726AD /* YGLayout+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "YGLayout+Private.h"; sourceTree = "<group>"; };
|
||||||
|
638A94441E1EF89C00A726AD /* YGValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YGValue.h; sourceTree = "<group>"; };
|
||||||
|
638A94461E1F06D100A726AD /* YogaKitSample-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "YogaKitSample-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
|
638A94471E1F06D100A726AD /* SwiftViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftViewController.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -109,6 +119,8 @@
|
|||||||
13687D4A1DF8748400E7C260 /* AppDelegate.m */,
|
13687D4A1DF8748400E7C260 /* AppDelegate.m */,
|
||||||
13687D4C1DF8748400E7C260 /* ViewController.h */,
|
13687D4C1DF8748400E7C260 /* ViewController.h */,
|
||||||
13687D4D1DF8748400E7C260 /* ViewController.m */,
|
13687D4D1DF8748400E7C260 /* ViewController.m */,
|
||||||
|
638A94471E1F06D100A726AD /* SwiftViewController.swift */,
|
||||||
|
638A94461E1F06D100A726AD /* YogaKitSample-Bridging-Header.h */,
|
||||||
13687D521DF8748400E7C260 /* Assets.xcassets */,
|
13687D521DF8748400E7C260 /* Assets.xcassets */,
|
||||||
13687D571DF8748400E7C260 /* Info.plist */,
|
13687D571DF8748400E7C260 /* Info.plist */,
|
||||||
13687D461DF8748400E7C260 /* Supporting Files */,
|
13687D461DF8748400E7C260 /* Supporting Files */,
|
||||||
@@ -127,6 +139,7 @@
|
|||||||
13687D5D1DF8778F00E7C260 /* yoga */ = {
|
13687D5D1DF8778F00E7C260 /* yoga */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
638A94441E1EF89C00A726AD /* YGValue.h */,
|
||||||
13687D5E1DF8778F00E7C260 /* YGEnums.h */,
|
13687D5E1DF8778F00E7C260 /* YGEnums.h */,
|
||||||
13687D5F1DF8778F00E7C260 /* YGMacros.h */,
|
13687D5F1DF8778F00E7C260 /* YGMacros.h */,
|
||||||
13687D601DF8778F00E7C260 /* YGNodeList.c */,
|
13687D601DF8778F00E7C260 /* YGNodeList.c */,
|
||||||
@@ -143,6 +156,9 @@
|
|||||||
children = (
|
children = (
|
||||||
13687D691DF8778F00E7C260 /* UIView+Yoga.h */,
|
13687D691DF8778F00E7C260 /* UIView+Yoga.h */,
|
||||||
13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */,
|
13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */,
|
||||||
|
638A94401E1EF5D000A726AD /* YGLayout.h */,
|
||||||
|
638A94421E1EF5D000A726AD /* YGLayout+Private.h */,
|
||||||
|
638A94411E1EF5D000A726AD /* YGLayout.m */,
|
||||||
);
|
);
|
||||||
name = YogaKit;
|
name = YogaKit;
|
||||||
path = ..;
|
path = ..;
|
||||||
@@ -185,11 +201,12 @@
|
|||||||
13687D3B1DF8748300E7C260 /* Project object */ = {
|
13687D3B1DF8748300E7C260 /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0810;
|
LastUpgradeCheck = 0820;
|
||||||
ORGANIZATIONNAME = facebook;
|
ORGANIZATIONNAME = facebook;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
13687D421DF8748300E7C260 = {
|
13687D421DF8748300E7C260 = {
|
||||||
CreatedOnToolsVersion = 8.1;
|
CreatedOnToolsVersion = 8.1;
|
||||||
|
LastSwiftMigration = 0820;
|
||||||
ProvisioningStyle = Automatic;
|
ProvisioningStyle = Automatic;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -228,12 +245,14 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
638A94481E1F06D100A726AD /* SwiftViewController.swift in Sources */,
|
||||||
13687D801DF87CEC00E7C260 /* UIView+Yoga.m in Sources */,
|
13687D801DF87CEC00E7C260 /* UIView+Yoga.m in Sources */,
|
||||||
13687D4E1DF8748400E7C260 /* ViewController.m in Sources */,
|
13687D4E1DF8748400E7C260 /* ViewController.m in Sources */,
|
||||||
13687D4B1DF8748400E7C260 /* AppDelegate.m in Sources */,
|
13687D4B1DF8748400E7C260 /* AppDelegate.m in Sources */,
|
||||||
13687D821DF87CF200E7C260 /* Yoga.c in Sources */,
|
13687D821DF87CF200E7C260 /* Yoga.c in Sources */,
|
||||||
13687D811DF87CF200E7C260 /* YGNodeList.c in Sources */,
|
13687D811DF87CF200E7C260 /* YGNodeList.c in Sources */,
|
||||||
13687D481DF8748400E7C260 /* main.m in Sources */,
|
13687D481DF8748400E7C260 /* main.m in Sources */,
|
||||||
|
638A94431E1EF5D000A726AD /* YGLayout.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@@ -258,6 +277,7 @@
|
|||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
@@ -305,6 +325,7 @@
|
|||||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||||
CLANG_WARN_INT_CONVERSION = YES;
|
CLANG_WARN_INT_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
CLANG_WARN_SUSPICIOUS_MOVES = YES;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
@@ -332,10 +353,14 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
INFOPLIST_FILE = YogaKitSample/Info.plist;
|
INFOPLIST_FILE = YogaKitSample/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
|
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "YogaKitSample/YogaKitSample-Bridging-Header.h";
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -343,10 +368,13 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
INFOPLIST_FILE = YogaKitSample/Info.plist;
|
INFOPLIST_FILE = YogaKitSample/Info.plist;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
|
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SWIFT_OBJC_BRIDGING_HEADER = "YogaKitSample/YogaKitSample-Bridging-Header.h";
|
||||||
|
SWIFT_VERSION = 3.0;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
@@ -369,6 +397,7 @@
|
|||||||
13687D5C1DF8748400E7C260 /* Release */,
|
13687D5C1DF8748400E7C260 /* Release */,
|
||||||
);
|
);
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
};
|
};
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2014-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the license found in the
|
||||||
|
* LICENSE-examples file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
class SwiftViewController: UIViewController {
|
||||||
|
override func viewDidLoad() {
|
||||||
|
let root = self.view!
|
||||||
|
root.backgroundColor = .red
|
||||||
|
root.yoga.isEnabled = true
|
||||||
|
root.yoga.width = self.view.bounds.size.width
|
||||||
|
root.yoga.height = self.view.bounds.size.height
|
||||||
|
root.yoga.alignItems = .center
|
||||||
|
root.yoga.justifyContent = .center
|
||||||
|
|
||||||
|
let child1 = UIView()
|
||||||
|
child1.backgroundColor = .blue
|
||||||
|
child1.yoga.isEnabled = true
|
||||||
|
child1.yoga.width = 100
|
||||||
|
child1.yoga.height = 10
|
||||||
|
|
||||||
|
let child2 = UIView()
|
||||||
|
child2.backgroundColor = .green
|
||||||
|
child2.frame = CGRect(x: 0, y: 0, width: 200, height: 100)
|
||||||
|
|
||||||
|
let child3 = UIView()
|
||||||
|
child3.backgroundColor = .yellow
|
||||||
|
child3.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
|
||||||
|
|
||||||
|
child2.addSubview(child3)
|
||||||
|
root.addSubview(child1)
|
||||||
|
root.addSubview(child2)
|
||||||
|
root.yoga.applyLayout()
|
||||||
|
}
|
||||||
|
}
|
@@ -20,17 +20,17 @@
|
|||||||
{
|
{
|
||||||
UIView *root = self.view;
|
UIView *root = self.view;
|
||||||
root.backgroundColor = [UIColor redColor];
|
root.backgroundColor = [UIColor redColor];
|
||||||
[root yg_setUsesYoga:YES];
|
root.yoga.isEnabled = YES;
|
||||||
[root yg_setWidth:self.view.bounds.size.width];
|
root.yoga.width = self.view.bounds.size.width;
|
||||||
[root yg_setHeight:self.view.bounds.size.height];
|
root.yoga.height = self.view.bounds.size.height;
|
||||||
[root yg_setAlignItems:YGAlignCenter];
|
root.yoga.alignItems = YGAlignCenter;
|
||||||
[root yg_setJustifyContent:YGJustifyCenter];
|
root.yoga.justifyContent = YGJustifyCenter;
|
||||||
|
|
||||||
UIView *child1 = [UIView new];
|
UIView *child1 = [UIView new];
|
||||||
child1.backgroundColor = [UIColor blueColor];
|
child1.backgroundColor = [UIColor blueColor];
|
||||||
[child1 yg_setUsesYoga:YES];
|
child1.yoga.isEnabled = YES;
|
||||||
[child1 yg_setWidth:100];
|
child1.yoga.width = 100;
|
||||||
[child1 yg_setHeight:100];
|
child1.yoga.height = 100;
|
||||||
|
|
||||||
UIView *child2 = [UIView new];
|
UIView *child2 = [UIView new];
|
||||||
child2.backgroundColor = [UIColor greenColor];
|
child2.backgroundColor = [UIColor greenColor];
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
[child2 addSubview:child3];
|
[child2 addSubview:child3];
|
||||||
[root addSubview:child1];
|
[root addSubview:child1];
|
||||||
[root addSubview:child2];
|
[root addSubview:child2];
|
||||||
[root yg_applyLayout];
|
[root.yoga applyLayout];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -0,0 +1,10 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2014-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the license found in the
|
||||||
|
* LICENSE-examples file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#import "UIView+Yoga.h"
|
||||||
|
#import <yoga/Yoga.h>
|
8
enums.py
8
enums.py
@@ -119,21 +119,21 @@ def to_java_upper(symbol):
|
|||||||
|
|
||||||
root = os.path.dirname(os.path.abspath(__file__))
|
root = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
|
||||||
# write out C headers
|
# write out C & Objective-C headers
|
||||||
with open(root + '/yoga/YGEnums.h', 'w') as f:
|
with open(root + '/yoga/YGEnums.h', 'w') as f:
|
||||||
f.write(LICENSE)
|
f.write(LICENSE)
|
||||||
f.write('#pragma once\n\n')
|
f.write('#pragma once\n\n')
|
||||||
f.write('#include "YGMacros.h"\n\n')
|
f.write('#include "YGMacros.h"\n\n')
|
||||||
f.write('YG_EXTERN_C_BEGIN\n\n')
|
f.write('YG_EXTERN_C_BEGIN\n\n')
|
||||||
for name, values in ENUMS.items():
|
for name, values in ENUMS.items():
|
||||||
f.write('#define YG%sCount %s\n' % (name, len(values)))
|
f.write('#define YG%sCount %s\n' % (name, len(values)))
|
||||||
f.write('typedef enum YG%s {\n' % name)
|
f.write('typedef YG_ENUM_BEGIN(YG%s) {\n' % name)
|
||||||
for value in values:
|
for value in values:
|
||||||
if isinstance(value, tuple):
|
if isinstance(value, tuple):
|
||||||
f.write(' YG%s%s = %d,\n' % (name, value[0], value[1]))
|
f.write(' YG%s%s = %d,\n' % (name, value[0], value[1]))
|
||||||
else:
|
else:
|
||||||
f.write(' YG%s%s,\n' % (name, value))
|
f.write(' YG%s%s,\n' % (name, value))
|
||||||
f.write('} YG%s;\n' % name)
|
f.write('} YG_ENUM_END(YG%s);\n' % name)
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
f.write('YG_EXTERN_C_END\n')
|
f.write('YG_EXTERN_C_END\n')
|
||||||
|
|
||||||
|
@@ -14,29 +14,29 @@
|
|||||||
YG_EXTERN_C_BEGIN
|
YG_EXTERN_C_BEGIN
|
||||||
|
|
||||||
#define YGFlexDirectionCount 4
|
#define YGFlexDirectionCount 4
|
||||||
typedef enum YGFlexDirection {
|
typedef YG_ENUM_BEGIN(YGFlexDirection) {
|
||||||
YGFlexDirectionColumn,
|
YGFlexDirectionColumn,
|
||||||
YGFlexDirectionColumnReverse,
|
YGFlexDirectionColumnReverse,
|
||||||
YGFlexDirectionRow,
|
YGFlexDirectionRow,
|
||||||
YGFlexDirectionRowReverse,
|
YGFlexDirectionRowReverse,
|
||||||
} YGFlexDirection;
|
} YG_ENUM_END(YGFlexDirection);
|
||||||
|
|
||||||
#define YGMeasureModeCount 3
|
#define YGMeasureModeCount 3
|
||||||
typedef enum YGMeasureMode {
|
typedef YG_ENUM_BEGIN(YGMeasureMode) {
|
||||||
YGMeasureModeUndefined,
|
YGMeasureModeUndefined,
|
||||||
YGMeasureModeExactly,
|
YGMeasureModeExactly,
|
||||||
YGMeasureModeAtMost,
|
YGMeasureModeAtMost,
|
||||||
} YGMeasureMode;
|
} YG_ENUM_END(YGMeasureMode);
|
||||||
|
|
||||||
#define YGPrintOptionsCount 3
|
#define YGPrintOptionsCount 3
|
||||||
typedef enum YGPrintOptions {
|
typedef YG_ENUM_BEGIN(YGPrintOptions) {
|
||||||
YGPrintOptionsLayout = 1,
|
YGPrintOptionsLayout = 1,
|
||||||
YGPrintOptionsStyle = 2,
|
YGPrintOptionsStyle = 2,
|
||||||
YGPrintOptionsChildren = 4,
|
YGPrintOptionsChildren = 4,
|
||||||
} YGPrintOptions;
|
} YG_ENUM_END(YGPrintOptions);
|
||||||
|
|
||||||
#define YGEdgeCount 9
|
#define YGEdgeCount 9
|
||||||
typedef enum YGEdge {
|
typedef YG_ENUM_BEGIN(YGEdge) {
|
||||||
YGEdgeLeft,
|
YGEdgeLeft,
|
||||||
YGEdgeTop,
|
YGEdgeTop,
|
||||||
YGEdgeRight,
|
YGEdgeRight,
|
||||||
@@ -46,79 +46,79 @@ typedef enum YGEdge {
|
|||||||
YGEdgeHorizontal,
|
YGEdgeHorizontal,
|
||||||
YGEdgeVertical,
|
YGEdgeVertical,
|
||||||
YGEdgeAll,
|
YGEdgeAll,
|
||||||
} YGEdge;
|
} YG_ENUM_END(YGEdge);
|
||||||
|
|
||||||
#define YGPositionTypeCount 2
|
#define YGPositionTypeCount 2
|
||||||
typedef enum YGPositionType {
|
typedef YG_ENUM_BEGIN(YGPositionType) {
|
||||||
YGPositionTypeRelative,
|
YGPositionTypeRelative,
|
||||||
YGPositionTypeAbsolute,
|
YGPositionTypeAbsolute,
|
||||||
} YGPositionType;
|
} YG_ENUM_END(YGPositionType);
|
||||||
|
|
||||||
#define YGDimensionCount 2
|
#define YGDimensionCount 2
|
||||||
typedef enum YGDimension {
|
typedef YG_ENUM_BEGIN(YGDimension) {
|
||||||
YGDimensionWidth,
|
YGDimensionWidth,
|
||||||
YGDimensionHeight,
|
YGDimensionHeight,
|
||||||
} YGDimension;
|
} YG_ENUM_END(YGDimension);
|
||||||
|
|
||||||
#define YGJustifyCount 5
|
#define YGJustifyCount 5
|
||||||
typedef enum YGJustify {
|
typedef YG_ENUM_BEGIN(YGJustify) {
|
||||||
YGJustifyFlexStart,
|
YGJustifyFlexStart,
|
||||||
YGJustifyCenter,
|
YGJustifyCenter,
|
||||||
YGJustifyFlexEnd,
|
YGJustifyFlexEnd,
|
||||||
YGJustifySpaceBetween,
|
YGJustifySpaceBetween,
|
||||||
YGJustifySpaceAround,
|
YGJustifySpaceAround,
|
||||||
} YGJustify;
|
} YG_ENUM_END(YGJustify);
|
||||||
|
|
||||||
#define YGDirectionCount 3
|
#define YGDirectionCount 3
|
||||||
typedef enum YGDirection {
|
typedef YG_ENUM_BEGIN(YGDirection) {
|
||||||
YGDirectionInherit,
|
YGDirectionInherit,
|
||||||
YGDirectionLTR,
|
YGDirectionLTR,
|
||||||
YGDirectionRTL,
|
YGDirectionRTL,
|
||||||
} YGDirection;
|
} YG_ENUM_END(YGDirection);
|
||||||
|
|
||||||
#define YGLogLevelCount 5
|
#define YGLogLevelCount 5
|
||||||
typedef enum YGLogLevel {
|
typedef YG_ENUM_BEGIN(YGLogLevel) {
|
||||||
YGLogLevelError,
|
YGLogLevelError,
|
||||||
YGLogLevelWarn,
|
YGLogLevelWarn,
|
||||||
YGLogLevelInfo,
|
YGLogLevelInfo,
|
||||||
YGLogLevelDebug,
|
YGLogLevelDebug,
|
||||||
YGLogLevelVerbose,
|
YGLogLevelVerbose,
|
||||||
} YGLogLevel;
|
} YG_ENUM_END(YGLogLevel);
|
||||||
|
|
||||||
#define YGWrapCount 2
|
#define YGWrapCount 2
|
||||||
typedef enum YGWrap {
|
typedef YG_ENUM_BEGIN(YGWrap) {
|
||||||
YGWrapNoWrap,
|
YGWrapNoWrap,
|
||||||
YGWrapWrap,
|
YGWrapWrap,
|
||||||
} YGWrap;
|
} YG_ENUM_END(YGWrap);
|
||||||
|
|
||||||
#define YGOverflowCount 3
|
#define YGOverflowCount 3
|
||||||
typedef enum YGOverflow {
|
typedef YG_ENUM_BEGIN(YGOverflow) {
|
||||||
YGOverflowVisible,
|
YGOverflowVisible,
|
||||||
YGOverflowHidden,
|
YGOverflowHidden,
|
||||||
YGOverflowScroll,
|
YGOverflowScroll,
|
||||||
} YGOverflow;
|
} YG_ENUM_END(YGOverflow);
|
||||||
|
|
||||||
#define YGExperimentalFeatureCount 2
|
#define YGExperimentalFeatureCount 2
|
||||||
typedef enum YGExperimentalFeature {
|
typedef YG_ENUM_BEGIN(YGExperimentalFeature) {
|
||||||
YGExperimentalFeatureRounding,
|
YGExperimentalFeatureRounding,
|
||||||
YGExperimentalFeatureWebFlexBasis,
|
YGExperimentalFeatureWebFlexBasis,
|
||||||
} YGExperimentalFeature;
|
} YG_ENUM_END(YGExperimentalFeature);
|
||||||
|
|
||||||
#define YGAlignCount 6
|
#define YGAlignCount 6
|
||||||
typedef enum YGAlign {
|
typedef YG_ENUM_BEGIN(YGAlign) {
|
||||||
YGAlignAuto,
|
YGAlignAuto,
|
||||||
YGAlignFlexStart,
|
YGAlignFlexStart,
|
||||||
YGAlignCenter,
|
YGAlignCenter,
|
||||||
YGAlignFlexEnd,
|
YGAlignFlexEnd,
|
||||||
YGAlignStretch,
|
YGAlignStretch,
|
||||||
YGAlignBaseline,
|
YGAlignBaseline,
|
||||||
} YGAlign;
|
} YG_ENUM_END(YGAlign);
|
||||||
|
|
||||||
#define YGUnitCount 3
|
#define YGUnitCount 3
|
||||||
typedef enum YGUnit {
|
typedef YG_ENUM_BEGIN(YGUnit) {
|
||||||
YGUnitUndefined,
|
YGUnitUndefined,
|
||||||
YGUnitPixel,
|
YGUnitPixel,
|
||||||
YGUnitPercent,
|
YGUnitPercent,
|
||||||
} YGUnit;
|
} YG_ENUM_END(YGUnit);
|
||||||
|
|
||||||
YG_EXTERN_C_END
|
YG_EXTERN_C_END
|
||||||
|
@@ -40,3 +40,19 @@
|
|||||||
YG_ABORT(); \
|
YG_ABORT(); \
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef YG_ENUM_BEGIN
|
||||||
|
#ifndef NS_ENUM
|
||||||
|
#define YG_ENUM_BEGIN(name) enum name
|
||||||
|
#else
|
||||||
|
#define YG_ENUM_BEGIN(name) NS_ENUM(NSInteger, name)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef YG_ENUM_END
|
||||||
|
#ifndef NS_ENUM
|
||||||
|
#define YG_ENUM_END(name) name
|
||||||
|
#else
|
||||||
|
#define YG_ENUM_END(name)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
Reference in New Issue
Block a user