Set nodes dirty when sizeThatFits changes
Summary: In YogaKit, nodes are not dirtied when `sizeThatFits` of leaf nodes change. This makes it difficult to reuse views like `UILabel` when their content (text) changes. I wrote a failing test to prove it and wrote a fix by caching the latest value of `sizeThatFits` in `YGNodeBridge` and checking for changes in `YGAttachNodesFromViewHierachy` (renamed to `YGUpdateNodesFromViewHierachy` to make it clear it's not simply reattaching nodes anymore). When a new size is detected, I call `YGNodeMarkDirty` on the leaf node. **Unfortunately**, this makes another test fail for no logical reason (`testThatViewNotIncludedInFirstLayoutPassAreIncludedInSecond`). Either there's something I don't understand or I've un-advertedly unearthed a bug in the C implementation, but in what case would setting a node dirty make the layout return a different size? Closes https://github.com/facebook/yoga/pull/308 Reviewed By: emilsjolander Differential Revision: D4378826 Pulled By: dshahidehpour fbshipit-source-id: cd0640bc863debb9e434370739416e3e33e57a08
This commit is contained in:
committed by
Facebook Github Bot
parent
1877a97898
commit
29c44e281c
@@ -96,6 +96,29 @@
|
|||||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(514,21), containerSize), @"Size is actually %@", NSStringFromCGSize(containerSize));
|
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
|
- (void)testFrameAndOriginPlacement
|
||||||
{
|
{
|
||||||
const CGSize containerSize = CGSizeMake(320, 50);
|
const CGSize containerSize = CGSizeMake(320, 50);
|
||||||
|
@@ -75,4 +75,9 @@
|
|||||||
*/
|
*/
|
||||||
- (BOOL)yg_isLeaf;
|
- (BOOL)yg_isLeaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Mark that a view's layout needs to be recalculated. Only works for leaf views.
|
||||||
|
*/
|
||||||
|
- (void)yg_markDirty;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
|
|
||||||
|
static const void *kYGNodeBridgeAssociatedKey = &kYGNodeBridgeAssociatedKey;
|
||||||
|
|
||||||
@interface YGNodeBridge : NSObject
|
@interface YGNodeBridge : NSObject
|
||||||
@property (nonatomic, assign, readonly) YGNodeRef cnode;
|
@property (nonatomic, assign, readonly) YGNodeRef cnode;
|
||||||
@end
|
@end
|
||||||
@@ -39,6 +41,14 @@
|
|||||||
|
|
||||||
@implementation UIView (Yoga)
|
@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
|
- (BOOL)yg_usesYoga
|
||||||
{
|
{
|
||||||
NSNumber *usesYoga = objc_getAssociatedObject(self, @selector(yg_usesYoga));
|
NSNumber *usesYoga = objc_getAssociatedObject(self, @selector(yg_usesYoga));
|
||||||
@@ -226,13 +236,12 @@
|
|||||||
|
|
||||||
- (YGNodeRef)ygNode
|
- (YGNodeRef)ygNode
|
||||||
{
|
{
|
||||||
YGNodeBridge *node = objc_getAssociatedObject(self, @selector(ygNode));
|
YGNodeBridge *node = objc_getAssociatedObject(self, kYGNodeBridgeAssociatedKey);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
node = [YGNodeBridge new];
|
node = [YGNodeBridge new];
|
||||||
YGNodeSetContext(node.cnode, (__bridge void *) self);
|
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;
|
return node.cnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user