diff --git a/YogaKit/Tests/YogaKitTests.m b/YogaKit/Tests/YogaKitTests.m index e4de239a..bdade66e 100644 --- a/YogaKit/Tests/YogaKitTests.m +++ b/YogaKit/Tests/YogaKitTests.m @@ -96,6 +96,29 @@ XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(514,21), containerSize), @"Size is actually %@", NSStringFromCGSize(containerSize)); } +- (void)testThatMarkingLeafsAsDirtyWillTriggerASizeRecalculation +{ + UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 50)]; + [container yg_setUsesYoga:YES]; + [container yg_setFlexDirection:YGFlexDirectionRow]; + [container yg_setAlignItems:YGAlignFlexStart]; + + UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; + label.text = @"This is a short text."; + label.numberOfLines = 1; + [label yg_setUsesYoga:YES]; + [container addSubview:label]; + + [container yg_applyLayout]; + XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(146,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size)); + + label.text = @"This is a slightly longer text."; + [label yg_markDirty]; + + [container yg_applyLayout]; + XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(213,21), label.bounds.size), @"Size is actually %@", NSStringFromCGSize(label.bounds.size)); +} + - (void)testFrameAndOriginPlacement { const CGSize containerSize = CGSizeMake(320, 50); diff --git a/YogaKit/UIView+Yoga.h b/YogaKit/UIView+Yoga.h index 3a5777ef..b565b1ae 100644 --- a/YogaKit/UIView+Yoga.h +++ b/YogaKit/UIView+Yoga.h @@ -75,4 +75,9 @@ */ - (BOOL)yg_isLeaf; +/** + Mark that a view's layout needs to be recalculated. Only works for leaf views. + */ +- (void)yg_markDirty; + @end diff --git a/YogaKit/UIView+Yoga.m b/YogaKit/UIView+Yoga.m index 9774d3e9..cfe0afa0 100644 --- a/YogaKit/UIView+Yoga.m +++ b/YogaKit/UIView+Yoga.m @@ -11,6 +11,8 @@ #import +static const void *kYGNodeBridgeAssociatedKey = &kYGNodeBridgeAssociatedKey; + @interface YGNodeBridge : NSObject @property (nonatomic, assign, readonly) YGNodeRef cnode; @end @@ -39,6 +41,14 @@ @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)); @@ -226,13 +236,12 @@ - (YGNodeRef)ygNode { - YGNodeBridge *node = objc_getAssociatedObject(self, @selector(ygNode)); + YGNodeBridge *node = objc_getAssociatedObject(self, kYGNodeBridgeAssociatedKey); if (!node) { node = [YGNodeBridge new]; YGNodeSetContext(node.cnode, (__bridge void *) self); - objc_setAssociatedObject(self, @selector(ygNode), node, OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(self, kYGNodeBridgeAssociatedKey, node, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - return node.cnode; }