diff --git a/uikit/CSSLayout/Tests/CSSLayoutTests.m b/uikit/CSSLayout/Tests/CSSLayoutTests.m index 1dfc5339..e9ce9b1d 100644 --- a/uikit/CSSLayout/Tests/CSSLayoutTests.m +++ b/uikit/CSSLayout/Tests/CSSLayoutTests.m @@ -78,4 +78,33 @@ XCTAssertTrue(CGSizeEqualToSize(constrainedSize, actualSize), @"Actual Size: %@", NSStringFromCGSize(actualSize)); } +- (void)testFrameAndOriginPlacement +{ + const CGSize containerSize = CGSizeMake(320, 50); + + UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, containerSize.width, containerSize.height)]; + [container css_setUsesFlexbox:YES]; + [container css_setFlexDirection:CSSFlexDirectionRow]; + + for (int i = 0; i < 3; i++) { + UIView *subview = [[UIView alloc] initWithFrame:CGRectZero]; + [subview css_setUsesFlexbox:YES]; + [subview css_setFlexGrow:1]; + + [container addSubview:subview]; + } + [container css_applyLayout]; + + 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:0].frame, [container.subviews objectAtIndex:2].frame)); + + CGFloat totalWidth = 0; + for (UIView *view in container.subviews) { + totalWidth += view.bounds.size.width; + } + + XCTAssertEqual(containerSize.width, totalWidth, @"The container's width is %.6f, the subviews take up %.6f", containerSize.width, totalWidth); +} + @end diff --git a/uikit/CSSLayout/UIView+CSSLayout.m b/uikit/CSSLayout/UIView+CSSLayout.m index af5b9965..d7ed0cc6 100644 --- a/uikit/CSSLayout/UIView+CSSLayout.m +++ b/uikit/CSSLayout/UIView+CSSLayout.m @@ -277,22 +277,43 @@ static void _attachNodesRecursive(UIView *view) { } } +static CGFloat _roundPixelValue(CGFloat value) +{ + static CGFloat scale; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^(){ + scale = [UIScreen mainScreen].scale; + }); + + return round(value * scale) / scale; +} + static void _updateFrameRecursive(UIView *view) { + NSAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread."); CSSNodeRef node = [view cssNode]; - const BOOL usesFlexbox = [view css_usesFlexbox]; - const BOOL isLeaf = !usesFlexbox || view.subviews.count == 0; + + const CGPoint topLeft = { + CSSNodeLayoutGetLeft(node), + CSSNodeLayoutGetTop(node), + }; + + const CGPoint bottomRight = { + topLeft.x + CSSNodeLayoutGetWidth(node), + topLeft.y + CSSNodeLayoutGetHeight(node), + }; view.frame = (CGRect) { .origin = { - .x = CSSNodeLayoutGetLeft(node), - .y = CSSNodeLayoutGetTop(node), + .x = _roundPixelValue(topLeft.x), + .y = _roundPixelValue(topLeft.y), }, .size = { - .width = CSSNodeLayoutGetWidth(node), - .height = CSSNodeLayoutGetHeight(node), + .width = _roundPixelValue(bottomRight.x) - _roundPixelValue(topLeft.x), + .height = _roundPixelValue(bottomRight.y) - _roundPixelValue(topLeft.y), }, }; + const BOOL isLeaf = ![view css_usesFlexbox] || view.subviews.count == 0; if (!isLeaf) { for (NSUInteger i = 0; i < view.subviews.count; i++) { _updateFrameRecursive(view.subviews[i]);