Move files around
This commit is contained in:
@@ -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);
|
||||
@@ -268,4 +291,97 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testyg_isLeafFlag
|
||||
{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
XCTAssertTrue(view.yg_isLeaf);
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[view addSubview:subview];
|
||||
}
|
||||
XCTAssertTrue(view.yg_isLeaf);
|
||||
|
||||
[view yg_setUsesYoga:YES];
|
||||
[view yg_setWidth:50.0];
|
||||
XCTAssertTrue(view.yg_isLeaf);
|
||||
|
||||
UIView *const subview = view.subviews[0];
|
||||
[subview yg_setUsesYoga:YES];
|
||||
[subview yg_setWidth:50.0];
|
||||
XCTAssertFalse(view.yg_isLeaf);
|
||||
}
|
||||
|
||||
- (void)testThatWeCorrectlyAttachNestedViews
|
||||
{
|
||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
||||
[container yg_setUsesYoga:YES];
|
||||
[container yg_setFlexDirection:YGFlexDirectionColumn];
|
||||
|
||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview1 yg_setUsesYoga:YES];
|
||||
[subview1 yg_setWidth:100];
|
||||
[subview1 yg_setFlexGrow:1];
|
||||
[subview1 yg_setFlexDirection:YGFlexDirectionColumn];
|
||||
[container addSubview:subview1];
|
||||
|
||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview2 yg_setUsesYoga:YES];
|
||||
[subview2 yg_setWidth:150];
|
||||
[subview2 yg_setFlexGrow:1];
|
||||
[subview2 yg_setFlexDirection:YGFlexDirectionColumn];
|
||||
[container addSubview:subview2];
|
||||
|
||||
for (UIView *view in @[subview1, subview2]) {
|
||||
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[someView yg_setUsesYoga:YES];
|
||||
[someView yg_setFlexGrow:1];
|
||||
[view addSubview:someView];
|
||||
}
|
||||
[container yg_applyLayout];
|
||||
|
||||
// Add the same amount of new views, reapply layout.
|
||||
for (UIView *view in @[subview1, subview2]) {
|
||||
UIView *someView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[someView yg_setUsesYoga:YES];
|
||||
[someView yg_setFlexGrow:1];
|
||||
[view addSubview:someView];
|
||||
}
|
||||
[container yg_applyLayout];
|
||||
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(100, 25), subview1.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview1.bounds.size));
|
||||
for (UIView *subview in subview1.subviews) {
|
||||
const CGSize subviewSize = subview.bounds.size;
|
||||
XCTAssertFalse(CGSizeEqualToSize(CGSizeZero, subviewSize));
|
||||
XCTAssertFalse(isnan(subviewSize.height));
|
||||
XCTAssertFalse(isnan(subviewSize.width));
|
||||
}
|
||||
|
||||
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(150, 25), subview2.bounds.size), @"Actual size is %@", NSStringFromCGSize(subview2.bounds.size));
|
||||
for (UIView *subview in subview2.subviews) {
|
||||
const CGSize subviewSize = subview.bounds.size;
|
||||
XCTAssertFalse(CGSizeEqualToSize(CGSizeZero, subview.bounds.size));
|
||||
XCTAssertFalse(isnan(subviewSize.height));
|
||||
XCTAssertFalse(isnan(subviewSize.width));
|
||||
}
|
||||
}
|
||||
|
||||
- (void)testThatANonLeafNodeCanBecomeALeafNode
|
||||
{
|
||||
UIView *container = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
|
||||
[container yg_setUsesYoga:YES];
|
||||
|
||||
UIView *subview1 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview1 yg_setUsesYoga:YES];
|
||||
[container addSubview:subview1];
|
||||
|
||||
UIView *subview2 = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview2 yg_setUsesYoga:YES];
|
||||
[subview1 addSubview:subview2];
|
||||
|
||||
[container yg_applyLayout];
|
||||
[subview2 removeFromSuperview];
|
||||
[container yg_applyLayout];
|
||||
}
|
||||
|
||||
@end
|
||||
|
@@ -30,6 +30,7 @@
|
||||
- (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;
|
||||
@@ -69,4 +70,14 @@
|
||||
*/
|
||||
- (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
|
||||
|
@@ -11,6 +11,8 @@
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
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));
|
||||
@@ -56,6 +66,20 @@
|
||||
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
|
||||
@@ -116,6 +140,11 @@
|
||||
YGNodeStyleSetFlexWrap([self ygNode], flexWrap);
|
||||
}
|
||||
|
||||
- (void)yg_setOverflow:(YGOverflow)overflow
|
||||
{
|
||||
YGNodeStyleSetOverflow([self ygNode], overflow);
|
||||
}
|
||||
|
||||
- (void)yg_setFlexGrow:(CGFloat)flexGrow
|
||||
{
|
||||
YGNodeStyleSetFlexGrow([self ygNode], flexGrow);
|
||||
@@ -207,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;
|
||||
}
|
||||
|
||||
@@ -276,17 +304,32 @@ static CGFloat YGSanitizeMeasurement(
|
||||
return result;
|
||||
}
|
||||
|
||||
static void YGAttachNodesFromViewHierachy(UIView *view) {
|
||||
YGNodeRef node = [view ygNode];
|
||||
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_usesYoga] || view.subviews.count == 0) {
|
||||
YGNodeSetMeasureFunc(node, YGMeasureView);
|
||||
if (view.yg_isLeaf) {
|
||||
YGRemoveAllChildren(node);
|
||||
YGNodeSetMeasureFunc(node, YGMeasureView);
|
||||
} else {
|
||||
YGNodeSetMeasureFunc(node, NULL);
|
||||
|
||||
// Create a list of all the subviews that we are going to use for layout.
|
||||
NSMutableArray<UIView *> *subviewsToInclude = [[NSMutableArray alloc] initWithCapacity:view.subviews.count];
|
||||
for (UIView *subview in view.subviews) {
|
||||
if ([subview yg_includeInLayout]) {
|
||||
@@ -294,26 +337,15 @@ static void YGAttachNodesFromViewHierachy(UIView *view) {
|
||||
}
|
||||
}
|
||||
|
||||
BOOL shouldReconstructChildList = NO;
|
||||
if (YGNodeGetChildCount(node) != subviewsToInclude.count) {
|
||||
shouldReconstructChildList = YES;
|
||||
} else {
|
||||
for (int i = 0; i < subviewsToInclude.count; i++) {
|
||||
if (YGNodeGetChild(node, i) != [subviewsToInclude[i] ygNode]) {
|
||||
shouldReconstructChildList = YES;
|
||||
break;
|
||||
if (!YGNodeHasExactSameChildren(node, subviewsToInclude)) {
|
||||
YGRemoveAllChildren(node);
|
||||
for (int i=0; i<subviewsToInclude.count; i++) {
|
||||
YGNodeInsertChild(node, [subviewsToInclude[i] ygNode], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReconstructChildList) {
|
||||
YGRemoveAllChildren(node);
|
||||
|
||||
for (int i = 0 ; i < subviewsToInclude.count; i++) {
|
||||
UIView *const subview = subviewsToInclude[i];
|
||||
YGNodeInsertChild(node, [subview ygNode], i);
|
||||
for (UIView *const subview in subviewsToInclude) {
|
||||
YGAttachNodesFromViewHierachy(subview);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,7 +372,8 @@ static CGFloat YGRoundPixelValue(CGFloat value)
|
||||
return round(value * scale) / scale;
|
||||
}
|
||||
|
||||
static void YGApplyLayoutToViewHierarchy(UIView *view) {
|
||||
static void YGApplyLayoutToViewHierarchy(UIView *view)
|
||||
{
|
||||
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
|
||||
if (![view yg_includeInLayout]) {
|
||||
return;
|
||||
@@ -368,9 +401,8 @@ static void YGApplyLayoutToViewHierarchy(UIView *view) {
|
||||
},
|
||||
};
|
||||
|
||||
const BOOL isLeaf = ![view yg_usesYoga] || view.subviews.count == 0;
|
||||
if (!isLeaf) {
|
||||
for (NSUInteger i = 0; i < view.subviews.count; i++) {
|
||||
if (!view.yg_isLeaf) {
|
||||
for (NSUInteger i=0; i<view.subviews.count; i++) {
|
||||
YGApplyLayoutToViewHierarchy(view.subviews[i]);
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
@@ -1,91 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0810"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13687D421DF8748300E7C260"
|
||||
BuildableName = "YogaKitSample.app"
|
||||
BlueprintName = "YogaKitSample"
|
||||
ReferencedContainer = "container:YogaKitSample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<Testables>
|
||||
</Testables>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13687D421DF8748300E7C260"
|
||||
BuildableName = "YogaKitSample.app"
|
||||
BlueprintName = "YogaKitSample"
|
||||
ReferencedContainer = "container:YogaKitSample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13687D421DF8748300E7C260"
|
||||
BuildableName = "YogaKitSample.app"
|
||||
BlueprintName = "YogaKitSample"
|
||||
ReferencedContainer = "container:YogaKitSample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Release"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13687D421DF8748300E7C260"
|
||||
BuildableName = "YogaKitSample.app"
|
||||
BlueprintName = "YogaKitSample"
|
||||
ReferencedContainer = "container:YogaKitSample.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>SchemeUserState</key>
|
||||
<dict>
|
||||
<key>YogaKitSample.xcscheme</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>13687D421DF8748300E7C260</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
Reference in New Issue
Block a user