WIP: Improve the Objective-C and Swift bridge #289

Closed
hartbit wants to merge 8 commits from improve-objc-swift into master
25 changed files with 850 additions and 587 deletions

3
.gitignore vendored
View File

@@ -8,3 +8,6 @@
# Visual studio code
.vscode
# Xcode
xcuserdata

View File

@@ -1,77 +0,0 @@
/**
* 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/Yoga.h>
@interface UIView (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_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;
@end

View File

@@ -1,397 +0,0 @@
/**
* 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 "UIView+Yoga.h"
#import <objc/runtime.h>
@interface YGNodeBridge : NSObject
@property (nonatomic, assign, readonly) YGNodeRef cnode;
@end
@implementation YGNodeBridge
+ (void)initialize
{
YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true);
}
- (instancetype)init
{
if ([super init]) {
_cnode = YGNodeNew();
}
return self;
}
- (void)dealloc
{
YGNodeFree(_cnode);
}
@end
@implementation UIView (Yoga)
- (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_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, @selector(ygNode));
if (!node) {
node = [YGNodeBridge new];
YGNodeSetContext(node.cnode, (__bridge void *) self);
objc_setAssociatedObject(self, @selector(ygNode), 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) {
YGNodeSetMeasureFunc(node, YGMeasureView);
YGRemoveAllChildren(node);
} 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

17
YogaKit/UIView+YogaKit.h Normal file
View File

@@ -0,0 +1,17 @@
/**
* 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 <YogaKit/YKLayout.h>
@interface UIView (YogaKit)
@property (nonatomic, readonly) YKLayout* layout;
@end

28
YogaKit/UIView+YogaKit.m Normal file
View File

@@ -0,0 +1,28 @@
/**
* 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 <YogaKit/UIView+YogaKit.h>
#import <YogaKit/YKLayout+Private.h>
#import <objc/runtime.h>
@implementation UIView (YogaKit)
- (YKLayout *)layout
{
YKLayout *layout = objc_getAssociatedObject(self, @selector(layout));
if (!layout) {
layout = [[YKLayout alloc] initWithView:self];
objc_setAssociatedObject(self, @selector(layout), layout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return layout;
}
@end

48
YogaKit/YKEnums.h Normal file
View File

@@ -0,0 +1,48 @@
/**
* 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.
*/
typedef NS_ENUM(NSInteger, YKFlexDirection) {
YKFlexDirectionColumn,
YKFlexDirectionColumnReverse,
YKFlexDirectionRow,
YKFlexDirectionRowReverse,
} NS_SWIFT_NAME(FlexDirection);
typedef NS_ENUM(NSInteger, YKPositionType) {
YKPositionTypeRelative,
YKPositionTypeAbsolute,
} NS_SWIFT_NAME(PositionType);
typedef NS_ENUM(NSInteger, YKJustify) {
YKJustifyFlexStart,
YKJustifyCenter,
YKJustifyFlexEnd,
YKJustifySpaceBetween,
YKJustifySpaceAround,
} NS_SWIFT_NAME(Justify);
typedef NS_ENUM(NSInteger, YKDirection) {
YKDirectionInherit,
YKDirectionLeftToRight,
YKDirectionRightToLeft,
} NS_SWIFT_NAME(Direction);
typedef NS_ENUM(NSInteger, YKWrap) {
YKWrapNoWrap,
YKWrapWrap,
} NS_SWIFT_NAME(Wrap);
typedef NS_ENUM(NSInteger, YKAlign) {
YKAlignAuto,
YKAlignFlexStart,
YKAlignCenter,
YKAlignFlexEnd,
YKAlignStretch,
} NS_SWIFT_NAME(Align);

View 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 <YogaKit/YKLayout.h>
@interface YKLayout ()
- (instancetype)initWithView:(UIView*)view;
@end

97
YogaKit/YKLayout.h Normal file
View File

@@ -0,0 +1,97 @@
/**
* 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 "YKEnums.h"
@interface YKLayout : NSObject
/**
The property that decides if we should include this view when calculating layout. Defaults to YES.
*/
@property (nonatomic, setter=setIncluded:) BOOL isIncluded;
/**
The property that decides during layout/sizing whether or not yk_* properties should be applied. Defaults to NO.
*/
@property (nonatomic, setter=setEnabled:) BOOL isEnabled;
@property (nonatomic) YKDirection direction;
@property (nonatomic) YKFlexDirection flexDirection;
@property (nonatomic) YKJustify justifyContent;
@property (nonatomic) YKAlign alignContent;
@property (nonatomic) YKAlign alignItems;
@property (nonatomic) YKAlign alignSelf;
@property (nonatomic) YKPositionType positionType;
@property (nonatomic) YKWrap flexWrap;
@property (nonatomic) CGFloat flexGrow;
@property (nonatomic) CGFloat flexShrink;
@property (nonatomic) CGFloat flexBasis;
@property (nonatomic) CGFloat positionLeft;
@property (nonatomic) CGFloat positionTop;
@property (nonatomic) CGFloat positionRight;
@property (nonatomic) CGFloat positionBottom;
@property (nonatomic) CGFloat positionStart;
@property (nonatomic) CGFloat positionEnd;
@property (nonatomic) CGFloat positionHorizontal;
d16r commented 2016-12-20 09:00:23 -08:00 (Migrated from github.com)
Review

Personally, I find this makes the API much more confusing. There are multiple properties that essentially do the same thing. I could set positionLeft and positionRight or just simply set positionHorizontal. To me, it would be much more idiomatic to Objective-C and Swift if we did something like this.

@property (nonatomic, readwrite, assign) UIEdgeInsets position;

or

- (void)setMargin:(CGFloat)margin forEdges:(YKEdges)edges;

where YKEdges is an NSOption.

I would apply this comment to margin and padding too. cc: @emilsjolander

Personally, I find this makes the API much more confusing. There are multiple properties that essentially do the same thing. I could set `positionLeft` and `positionRight` or just simply set `positionHorizontal`. To me, it would be much more idiomatic to Objective-C and Swift if we did something like this. ```objc @property (nonatomic, readwrite, assign) UIEdgeInsets position; ``` or ```objc - (void)setMargin:(CGFloat)margin forEdges:(YKEdges)edges; ``` where YKEdges is an NSOption. I would apply this comment to `margin` and `padding` too. cc: @emilsjolander
hartbit commented 2016-12-20 13:00:44 -08:00 (Migrated from github.com)
Review

@dshahidehpour I agree the solution I have is not ideal, but I fail to see how UIEdgeInsets or a NS_OPTIONS YKEdges would allow us to express the Start and End values.

@dshahidehpour I agree the solution I have is not ideal, but I fail to see how `UIEdgeInsets` or a `NS_OPTIONS YKEdges` would allow us to express the `Start` and `End` values.
d16r commented 2016-12-20 15:29:12 -08:00 (Migrated from github.com)
Review

@hartbit Whoops, I didn't even notice those, do we think they need to part of YogaKit? I purposely left some properties out at first because I didn't see a huge use-case for them with UIKit.

@hartbit Whoops, I didn't even notice those, do we think they need to part of `YogaKit`? I purposely left some properties out at first because I didn't see a huge use-case for them with UIKit.
hartbit commented 2016-12-20 16:21:51 -08:00 (Migrated from github.com)
Review

@dshahidehpour The Yoga website says: "We believe that Right-to-Left (RTL) should be a first class citizen when it comes to layout" and I strongly agree. UIKit also supports it by default with leading and trailing constraints in Auto Layout and I'd be very sorry to have them out of YogaKit.

You mention that there are multiple properties that do the same thing. But it's not unheard of in Cocoa. For example, a UIView's frame.size is the same as its bounds.size. Setting one affects the other. And it's the same with it's center, which is the mid-x and mid-y of frame.

I know, this is a difficult design decision. But I think there is no perfect solution. For sake of discussion, here are the solutions I see, as well as their pros and cons.

Properties

@property (nonatomic) CGFloat paddingLeft;
@property (nonatomic) CGFloat paddingRight;
@property (nonatomic) CGFloat paddingTop;
@property (nonatomic) CGFloat paddingBottom;
@property (nonatomic) CGFloat paddingStart;
@property (nonatomic) CGFloat paddingEnd;
@property (nonatomic) CGFloat paddingHorizontal;
@property (nonatomic) CGFloat paddingVertical;
@property (nonatomic) CGFloat padding; // I've removed the All because it's a change I'd like to do

Usage in Objective-C

view.layout.padding = 15;
// OR
view.layout.paddingTop = 10;
// OR
view.layout.paddingStart = 10;
// OR
view.layout.paddingHorizontal = 10;
view.layout.paddingTop = 15;

Usage in Swift

view.layout.padding = 15
// OR
view.layout.paddingTop = 10
// OR
view.layout.paddingStart = 10
// OR
view.layout.paddingHorizontal = 10
view.layout.paddingTop = 10

Pros

  • Recognizable API for people from CSS and React Native (it's actually the exact same API as React Native).
  • Auto-completion makes this API version fast to use, as for all other properties.

Cons

  • Makes the API surface larger, not very DRY.

Methods with NS_ENUM

- (CGFloat)paddingForEdge:(YGEdge)edge;
- (void)setPadding:(CGFloat)padding forEdge:(YGEdge)edge;

Usage in Objective-C

[view.layout setPadding:15 forEdge:YGEdgeAll];
// OR
[view.layout setPadding:10 forEdge:YGEdgeTop];
// OR
// NO WAY TO SET START
[view.layout setPadding:10 forEdge:YKEdgeHorizontal];
[view.layout setPadding:10 forEdge:YKEdgeTop];

Usage in Swift

view.layout.setPadding(15, for: .all)
// OR
view.layout.setPadding(10, for: .top)
// OR
// NO WAY TO SET START
// OR
view.layout.setPadding(10, for: .horizontal)
view.layout.setPadding(10, for: .top)

Pros

  • The usage looks cleaner by having a smaller API surface area.

Cons

  • We can't use dot-notation like all other properties, which breaks the reading flow. Perhaps it's my personal taste, but I see that as a big minus.
root.layout.width = 5;
[root.layout setPadding:10 forEdge:YGEdgeTop];
root.layout.flexGrow = 1;

YGEdgeValue


@interface YGEdgeValue
@property (nonatomic) CGFloat left;
@property (nonatomic) CGFloat right;
@property (nonatomic) CGFloat top;
@property (nonatomic) CGFloat bottom;
@property (nonatomic) CGFloat start;
@property (nonatomic) CGFloat end;
@property (nonatomic) CGFloat horizontal;
@property (nonatomic) CGFloat vertical;
@property (nonatomic) CGFloat all;
@end

@inteface YGLayout
@property (nonatomic, readonly) YGEdgeValue *padding;
@end

Usage in Objective-C

view.layout.padding.all = 15;
// OR
view.layout.padding.top = 10;
// OR
view.layout.padding.start = 10;
// OR
view.layout.padding.horizontal = 10;
view.layout.padding.top = 15;

Usage in Swift

view.layout.padding.all = 15
// OR
view.layout.padding.top = 10
// OR
view.layout.padding.start = 10
// OR
view.layout.padding.horizontal = 10
view.layout.padding.top = 10

Pros and Cons

This is basically a different flavor of properties. I'm not a hug fan of it because it multiplies the number of objects on the heap that yoga generates by 4 for a small gain in readability and API surface and a small loss in usage typing speed because having to go through two auto-completion hints (padding, then top).

Conclusion

On and all, here's my ranking of preference:

  1. Properties
  2. YGEdgeValue
  3. Methods
@dshahidehpour The Yoga website says: "We believe that Right-to-Left (RTL) should be a first class citizen when it comes to layout" and I strongly agree. UIKit also supports it by default with leading and trailing constraints in Auto Layout and I'd be very sorry to have them out of YogaKit. You mention that there are multiple properties that do the same thing. But it's not unheard of in Cocoa. For example, a UIView's `frame.size` is the same as its `bounds.size`. Setting one affects the other. And it's the same with it's `center`, which is the mid-x and mid-y of `frame`. I know, this is a difficult design decision. But I think there is no perfect solution. For sake of discussion, here are the solutions I see, as well as their pros and cons. # Properties ``` @property (nonatomic) CGFloat paddingLeft; @property (nonatomic) CGFloat paddingRight; @property (nonatomic) CGFloat paddingTop; @property (nonatomic) CGFloat paddingBottom; @property (nonatomic) CGFloat paddingStart; @property (nonatomic) CGFloat paddingEnd; @property (nonatomic) CGFloat paddingHorizontal; @property (nonatomic) CGFloat paddingVertical; @property (nonatomic) CGFloat padding; // I've removed the All because it's a change I'd like to do ``` ## Usage in Objective-C ``` view.layout.padding = 15; // OR view.layout.paddingTop = 10; // OR view.layout.paddingStart = 10; // OR view.layout.paddingHorizontal = 10; view.layout.paddingTop = 15; ``` ## Usage in Swift ``` view.layout.padding = 15 // OR view.layout.paddingTop = 10 // OR view.layout.paddingStart = 10 // OR view.layout.paddingHorizontal = 10 view.layout.paddingTop = 10 ``` ## Pros * Recognizable API for people from CSS and React Native (it's actually the exact same API as React Native). * Auto-completion makes this API version fast to use, as for all other properties. ## Cons * Makes the API surface larger, not very DRY. # Methods with `NS_ENUM` ``` - (CGFloat)paddingForEdge:(YGEdge)edge; - (void)setPadding:(CGFloat)padding forEdge:(YGEdge)edge; ``` ## Usage in Objective-C ``` [view.layout setPadding:15 forEdge:YGEdgeAll]; // OR [view.layout setPadding:10 forEdge:YGEdgeTop]; // OR // NO WAY TO SET START [view.layout setPadding:10 forEdge:YKEdgeHorizontal]; [view.layout setPadding:10 forEdge:YKEdgeTop]; ``` ## Usage in Swift ``` view.layout.setPadding(15, for: .all) // OR view.layout.setPadding(10, for: .top) // OR // NO WAY TO SET START // OR view.layout.setPadding(10, for: .horizontal) view.layout.setPadding(10, for: .top) ``` ## Pros * The usage looks cleaner by having a smaller API surface area. ## Cons * We can't use dot-notation like all other properties, which breaks the reading flow. Perhaps it's my personal taste, but I see that as a big minus. ``` root.layout.width = 5; [root.layout setPadding:10 forEdge:YGEdgeTop]; root.layout.flexGrow = 1; ``` # `YGEdgeValue` ``` @interface YGEdgeValue @property (nonatomic) CGFloat left; @property (nonatomic) CGFloat right; @property (nonatomic) CGFloat top; @property (nonatomic) CGFloat bottom; @property (nonatomic) CGFloat start; @property (nonatomic) CGFloat end; @property (nonatomic) CGFloat horizontal; @property (nonatomic) CGFloat vertical; @property (nonatomic) CGFloat all; @end @inteface YGLayout @property (nonatomic, readonly) YGEdgeValue *padding; @end ``` ## Usage in Objective-C ``` view.layout.padding.all = 15; // OR view.layout.padding.top = 10; // OR view.layout.padding.start = 10; // OR view.layout.padding.horizontal = 10; view.layout.padding.top = 15; ``` ## Usage in Swift ``` view.layout.padding.all = 15 // OR view.layout.padding.top = 10 // OR view.layout.padding.start = 10 // OR view.layout.padding.horizontal = 10 view.layout.padding.top = 10 ``` ## Pros and Cons This is basically a different flavor of properties. I'm not a hug fan of it because it multiplies the number of objects on the heap that yoga generates by 4 for a small gain in readability and API surface and a small loss in usage typing speed because having to go through two auto-completion hints (`padding`, then `top`). # Conclusion On and all, here's my ranking of preference: 1. Properties 2. YGEdgeValue 3. Methods
hartbit commented 2016-12-20 16:34:24 -08:00 (Migrated from github.com)
Review

As an additional support for the properties, I don't think it would surprise UIKit users because it is fairly idiomatic of the AutoLayout APIs:

screen shot 2016-12-21 at 01 31 09

Add to that the fact that CSS and React Native users would feel right a home.

As an additional support for the properties, I don't think it would surprise UIKit users because it is fairly idiomatic of the AutoLayout APIs: <img width="368" alt="screen shot 2016-12-21 at 01 31 09" src="https://cloud.githubusercontent.com/assets/325519/21373209/5f647db0-c71d-11e6-8cac-5853287cbeec.png"> Add to that the fact that CSS and React Native users would feel right a home.
d16r commented 2016-12-22 06:20:39 -08:00 (Migrated from github.com)
Review

Hey @hartbit, sorry I took so long to respond. I really appreciate the time you put into that response, and I support all of it 100%.

@emilsjolander I know we talked about YGEdgeValue, but, I think @hartbit makes a compelling case for why we should put these properties on the layout object.

  1. Matches other UIKit APIs.
  2. Less objects on the heap.
  3. One less method lookup when we are getting/setting this on the objc runtime.
Hey @hartbit, sorry I took so long to respond. I really appreciate the time you put into that response, and I support all of it 100%. @emilsjolander I know we talked about `YGEdgeValue`, but, I think @hartbit makes a compelling case for why we should put these properties on the layout object. 1. Matches other UIKit APIs. 2. Less objects on the heap. 3. One less method lookup when we are getting/setting this on the objc runtime.
eklipse2k8 commented 2017-01-03 11:37:41 -08:00 (Migrated from github.com)
Review

I like the YGEdgeValue the best, but why does it need to be a full class? In C/C++, the pattern would be lightweight structs for this kind of data set. That way I can do something like:

view.layout.padding = {.top = 10, .bottom = 10}

Or a hypothetical
view.layout.padding = YGCreateEdgeValues(...);

I like the YGEdgeValue the best, but why does it need to be a full class? In C/C++, the pattern would be lightweight structs for this kind of data set. That way I can do something like: `view.layout.padding = {.top = 10, .bottom = 10}` Or a hypothetical `view.layout.padding = YGCreateEdgeValues(...);`
@property (nonatomic) CGFloat positionVertical;
@property (nonatomic) CGFloat positionAll;
@property (nonatomic) CGFloat marginLeft;
@property (nonatomic) CGFloat marginTop;
@property (nonatomic) CGFloat marginRight;
@property (nonatomic) CGFloat marginBottom;
@property (nonatomic) CGFloat marginStart;
@property (nonatomic) CGFloat marginEnd;
@property (nonatomic) CGFloat marginHorizontal;
@property (nonatomic) CGFloat marginVertical;
@property (nonatomic) CGFloat marginAll;
@property (nonatomic) CGFloat paddingLeft;
@property (nonatomic) CGFloat paddingTop;
@property (nonatomic) CGFloat paddingRight;
@property (nonatomic) CGFloat paddingBottom;
@property (nonatomic) CGFloat paddingStart;
d16r commented 2016-12-20 09:02:54 -08:00 (Migrated from github.com)
Review

nit across the board, can we explicity add all the properties? i.e.

@property (nonatomic, readwrite, assign) ...
nit across the board, can we explicity add all the properties? i.e. ``` @property (nonatomic, readwrite, assign) ... ```
hartbit commented 2016-12-20 13:00:55 -08:00 (Migrated from github.com)
Review

Sure!

Sure!
@property (nonatomic) CGFloat paddingEnd;
@property (nonatomic) CGFloat paddingHorizontal;
@property (nonatomic) CGFloat paddingVertical;
@property (nonatomic) CGFloat paddingAll;
@property (nonatomic) CGFloat width;
@property (nonatomic) CGFloat height;
@property (nonatomic) CGFloat minWidth;
@property (nonatomic) CGFloat minHeight;
@property (nonatomic) CGFloat maxWidth;
@property (nonatomic) CGFloat maxHeight;
// Yoga specific properties, not compatible with flexbox specification
@property (nonatomic) CGFloat aspectRatio;
/**
Get the resolved direction of this node. This won't be YGDirectionInherit
*/
@property (nonatomic, readonly) YKDirection resolvedDirection;
/**
Perform a layout calculation and update the frames of the views in the hierarchy with the results
*/
- (void)apply;
/**
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) CGSize intrinsicSize;
/**
Returns the number of children that are using Flexbox.
*/
@property (nonatomic, readonly) NSUInteger numberOfChildren;
@end

294
YogaKit/YKLayout.m Normal file
View File

@@ -0,0 +1,294 @@
/**
* 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 <YogaKit/UIView+YogaKit.h>
#import <YogaKit/YKLayout.h>
#import <YogaKit/yoga.h>
#define YK_STYLE_PROPERTY_IMPL(objc_type, c_type, lowercased_name, capitalized_name) \
- (objc_type)lowercased_name \
{ \
return (objc_type)YGNodeStyleGet##capitalized_name(_node); \
} \
\
- (void)set##capitalized_name:(objc_type)lowercased_name \
{ \
YGNodeStyleSet##capitalized_name(_node, (c_type)lowercased_name); \
}
#define _YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, edge) \
- (CGFloat)lowercased_name##edge \
{ \
return YGNodeStyleGet##capitalized_name(_node, YGEdge##edge); \
} \
\
- (void)set##capitalized_name##edge:(CGFloat)lowercased_name##edge \
{ \
YGNodeStyleSet##capitalized_name(_node, YGEdge##edge, lowercased_name##edge); \
}
#define YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Left) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Top) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Right) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Bottom) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Start) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, End) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Horizontal) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, Vertical) \
_YK_STYLE_EDGE_PROPERTY_IMPL(lowercased_name, capitalized_name, All)
@interface YKLayout ()
@property (nonatomic, weak, readonly) UIView* view;
@property (nonatomic, assign, readonly) YGNodeRef node;
@end
@implementation YKLayout
@synthesize isEnabled=_isEnabled;
@synthesize isIncluded=_isIncluded;
+ (void)initialize
{
YGSetExperimentalFeatureEnabled(YGExperimentalFeatureWebFlexBasis, true);
}
- (instancetype)initWithView:(UIView*)view
{
if ([super init]) {
_view = view;
_node = YGNodeNew();
YGNodeSetContext(_node, (__bridge void *) view);
_isEnabled = NO;
_isIncluded = YES;
}
return self;
}
- (void)dealloc
{
YGNodeFree(_node);
}
- (NSUInteger)numberOfChildren
{
return YGNodeGetChildCount(_node);
}
YK_STYLE_PROPERTY_IMPL(YKDirection, YGDirection, direction, Direction)
YK_STYLE_PROPERTY_IMPL(YKFlexDirection, YGFlexDirection, flexDirection, FlexDirection)
YK_STYLE_PROPERTY_IMPL(YKJustify, YGJustify, justifyContent, JustifyContent)
YK_STYLE_PROPERTY_IMPL(YKAlign, YGAlign, alignContent, AlignContent)
YK_STYLE_PROPERTY_IMPL(YKAlign, YGAlign, alignItems, AlignItems)
YK_STYLE_PROPERTY_IMPL(YKAlign, YGAlign, alignSelf, AlignSelf)
YK_STYLE_PROPERTY_IMPL(YKPositionType, YGPositionType, positionType, PositionType)
YK_STYLE_PROPERTY_IMPL(YKWrap, YGWrap, flexWrap, FlexWrap)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, flexGrow, FlexGrow)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, flexShrink, FlexShrink)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, flexBasis, FlexBasis)
YK_STYLE_EDGE_PROPERTY_IMPL(position, Position)
YK_STYLE_EDGE_PROPERTY_IMPL(margin, Margin)
YK_STYLE_EDGE_PROPERTY_IMPL(padding, Padding)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, width, Width)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, height, Height)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, minWidth, MinWidth)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, minHeight, MinHeight)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, maxWidth, MaxWidth)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, maxHeight, MaxHeight)
YK_STYLE_PROPERTY_IMPL(CGFloat, CGFloat, aspectRatio, AspectRatio)
#pragma mark - Layout and Sizing
- (YKDirection)resolvedDirection
{
return (YKDirection)YGNodeLayoutGetDirection(_node);
}
- (void)apply
{
[self calculateLayoutWithSize:self.view.bounds.size];
YKApplyLayoutToViewHierarchy(self);
}
- (CGSize)intrinsicSize
{
const CGSize constrainedSize = {
.width = YGUndefined,
.height = YGUndefined,
};
return [self calculateLayoutWithSize:constrainedSize];
}
#pragma mark - Private
- (CGSize)calculateLayoutWithSize:(CGSize)size
{
NSAssert([NSThread isMainThread], @"YG Layout calculation must be done on main.");
NSAssert([self isEnabled], @"YG Layout is not enabled for this view.");
YKAttachNodesFromViewHierachy(self);
const YGNodeRef node = _node;
YGNodeCalculateLayout(
node,
size.width,
size.height,
YGNodeStyleGetDirection(node));
return (CGSize) {
.width = YGNodeLayoutGetWidth(node),
.height = YGNodeLayoutGetHeight(node),
};
}
static YGSize YKMeasureView(
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 = YKSanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
.height = YKSanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
};
}
static CGFloat YKSanitizeMeasurement(
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 void YKAttachNodesFromViewHierachy(YKLayout *layout) {
YGNodeRef node = layout.node;
UIView *view = layout.view;
// Only leaf nodes should have a measure function
if (![layout isEnabled] || view.subviews.count == 0) {
YGNodeSetMeasureFunc(node, YKMeasureView);
YKRemoveAllChildren(node);
} 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.layout.isIncluded) {
[subviewsToInclude addObject:subview];
}
}
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].layout.node) {
shouldReconstructChildList = YES;
break;
}
}
}
if (shouldReconstructChildList) {
YKRemoveAllChildren(node);
for (int i = 0 ; i < subviewsToInclude.count; i++) {
UIView *const subview = subviewsToInclude[i];
YGNodeInsertChild(node, subview.layout.node, i);
YKAttachNodesFromViewHierachy(subview.layout);
}
}
}
}
static void YKRemoveAllChildren(const YGNodeRef node)
{
if (node == NULL) {
return;
}
while (YGNodeGetChildCount(node) > 0) {
YGNodeRemoveChild(node, YGNodeGetChild(node, YGNodeGetChildCount(node) - 1));
}
}
static CGFloat YKRoundPixelValue(CGFloat value)
{
static CGFloat scale;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^(){
scale = [UIScreen mainScreen].scale;
});
return round(value * scale) / scale;
}
static void YKApplyLayoutToViewHierarchy(YKLayout *layout) {
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
if (!layout.isIncluded) {
return;
}
YGNodeRef node = layout.node;
const CGPoint topLeft = {
YGNodeLayoutGetLeft(node),
YGNodeLayoutGetTop(node),
};
const CGPoint bottomRight = {
topLeft.x + YGNodeLayoutGetWidth(node),
topLeft.y + YGNodeLayoutGetHeight(node),
};
UIView *view = layout.view;
view.frame = (CGRect) {
.origin = {
.x = YKRoundPixelValue(topLeft.x),
.y = YKRoundPixelValue(topLeft.y),
},
.size = {
.width = YKRoundPixelValue(bottomRight.x) - YKRoundPixelValue(topLeft.x),
.height = YKRoundPixelValue(bottomRight.y) - YKRoundPixelValue(topLeft.y),
},
};
const BOOL isLeaf = !layout.isEnabled || view.subviews.count == 0;
if (!isLeaf) {
for (NSUInteger i = 0; i < view.subviews.count; i++) {
YKApplyLayoutToViewHierarchy(view.subviews[i].layout);
}
}
}
@end

View File

@@ -11,40 +11,45 @@
13687D4B1DF8748400E7C260 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D4A1DF8748400E7C260 /* AppDelegate.m */; };
13687D4E1DF8748400E7C260 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D4D1DF8748400E7C260 /* ViewController.m */; };
13687D531DF8748400E7C260 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13687D521DF8748400E7C260 /* Assets.xcassets */; };
13687D781DF878C600E7C260 /* YGEnums.h in yoga */ = {isa = PBXBuildFile; fileRef = 13687D5E1DF8778F00E7C260 /* YGEnums.h */; };
13687D791DF878C600E7C260 /* YGMacros.h in yoga */ = {isa = PBXBuildFile; fileRef = 13687D5F1DF8778F00E7C260 /* YGMacros.h */; };
13687D7A1DF878C600E7C260 /* Yoga.h in yoga */ = {isa = PBXBuildFile; fileRef = 13687D631DF8778F00E7C260 /* Yoga.h */; };
13687D7C1DF878DD00E7C260 /* UIView+Yoga.h in YogaKit */ = {isa = PBXBuildFile; fileRef = 13687D691DF8778F00E7C260 /* UIView+Yoga.h */; };
13687D801DF87CEC00E7C260 /* UIView+Yoga.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */; };
13687D811DF87CF200E7C260 /* YGNodeList.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D601DF8778F00E7C260 /* YGNodeList.c */; };
13687D821DF87CF200E7C260 /* Yoga.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D621DF8778F00E7C260 /* Yoga.c */; };
13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D841DF87D1E00E7C260 /* UIKit.framework */; };
13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 13687D861DF87D2400E7C260 /* Foundation.framework */; };
63EE08411E06ED3D00EE5F9A /* YogaKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE083F1E06ED3D00EE5F9A /* YogaKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
63EE08441E06ED3D00EE5F9A /* YogaKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */; };
63EE08451E06ED3D00EE5F9A /* YogaKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
63EE084A1E06EEB700EE5F9A /* YGNodeList.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D601DF8778F00E7C260 /* YGNodeList.c */; };
63EE084B1E06EEB700EE5F9A /* Yoga.c in Sources */ = {isa = PBXBuildFile; fileRef = 13687D621DF8778F00E7C260 /* Yoga.c */; };
63EE084C1E06EEB700EE5F9A /* UIView+YogaKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 13687D6A1DF8778F00E7C260 /* UIView+YogaKit.m */; };
63EE084E1E06EECB00EE5F9A /* YGMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D5F1DF8778F00E7C260 /* YGMacros.h */; };
63EE084F1E06EECB00EE5F9A /* YGNodeList.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D611DF8778F00E7C260 /* YGNodeList.h */; };
63EE08501E06EECB00EE5F9A /* Yoga.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D631DF8778F00E7C260 /* Yoga.h */; };
63EE08511E06EECB00EE5F9A /* UIView+YogaKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 13687D691DF8778F00E7C260 /* UIView+YogaKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
63EE08531E06F3D100EE5F9A /* YKEnums.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE08521E06F3D100EE5F9A /* YKEnums.h */; settings = {ATTRIBUTES = (Public, ); }; };
63EE08551E072EF800EE5F9A /* SwiftViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63EE08541E072EF800EE5F9A /* SwiftViewController.swift */; };
63EE08571E07590C00EE5F9A /* YKLayout.m in Sources */ = {isa = PBXBuildFile; fileRef = 63EE08561E07590C00EE5F9A /* YKLayout.m */; };
63EE08591E07598A00EE5F9A /* YKLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE08581E07591A00EE5F9A /* YKLayout.h */; settings = {ATTRIBUTES = (Public, ); }; };
63EE085B1E075B0B00EE5F9A /* YKLayout+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 63EE085A1E075AAA00EE5F9A /* YKLayout+Private.h */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
13687D771DF878A000E7C260 /* yoga */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = include/yoga;
dstSubfolderSpec = 16;
files = (
13687D781DF878C600E7C260 /* YGEnums.h in yoga */,
13687D791DF878C600E7C260 /* YGMacros.h in yoga */,
13687D7A1DF878C600E7C260 /* Yoga.h in yoga */,
);
name = yoga;
runOnlyForDeploymentPostprocessing = 0;
/* Begin PBXContainerItemProxy section */
63EE08421E06ED3D00EE5F9A /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13687D3B1DF8748300E7C260 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 63EE083C1E06ED3D00EE5F9A;
remoteInfo = YogaKit;
};
13687D7B1DF878CE00E7C260 /* YogaKit */ = {
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
63EE08491E06ED3D00EE5F9A /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = include/YogaKit;
dstSubfolderSpec = 16;
dstPath = "";
dstSubfolderSpec = 10;
files = (
13687D7C1DF878DD00E7C260 /* UIView+Yoga.h in YogaKit */,
63EE08451E06ED3D00EE5F9A /* YogaKit.framework in Embed Frameworks */,
);
name = YogaKit;
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
@@ -58,16 +63,23 @@
13687D4D1DF8748400E7C260 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
13687D521DF8748400E7C260 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
13687D571DF8748400E7C260 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
13687D5E1DF8778F00E7C260 /* YGEnums.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YGEnums.h; sourceTree = "<group>"; };
13687D5F1DF8778F00E7C260 /* YGMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YGMacros.h; sourceTree = "<group>"; };
13687D601DF8778F00E7C260 /* YGNodeList.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = YGNodeList.c; sourceTree = "<group>"; };
13687D611DF8778F00E7C260 /* YGNodeList.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YGNodeList.h; sourceTree = "<group>"; };
13687D621DF8778F00E7C260 /* Yoga.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = Yoga.c; sourceTree = "<group>"; };
13687D631DF8778F00E7C260 /* Yoga.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Yoga.h; sourceTree = "<group>"; };
13687D691DF8778F00E7C260 /* UIView+Yoga.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+Yoga.h"; sourceTree = "<group>"; };
13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+Yoga.m"; sourceTree = "<group>"; };
13687D691DF8778F00E7C260 /* UIView+YogaKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "UIView+YogaKit.h"; path = "../../UIView+YogaKit.h"; sourceTree = "<group>"; };
13687D6A1DF8778F00E7C260 /* UIView+YogaKit.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "UIView+YogaKit.m"; path = "../../UIView+YogaKit.m"; sourceTree = "<group>"; };
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; };
63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = YogaKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
63EE083F1E06ED3D00EE5F9A /* YogaKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YogaKit.h; sourceTree = "<group>"; };
63EE08401E06ED3D00EE5F9A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
63EE08521E06F3D100EE5F9A /* YKEnums.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = YKEnums.h; path = ../../YKEnums.h; sourceTree = "<group>"; };
63EE08541E072EF800EE5F9A /* SwiftViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftViewController.swift; sourceTree = "<group>"; };
63EE08561E07590C00EE5F9A /* YKLayout.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = YKLayout.m; path = ../../YKLayout.m; sourceTree = "<group>"; };
63EE08581E07591A00EE5F9A /* YKLayout.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = YKLayout.h; path = ../../YKLayout.h; sourceTree = "<group>"; };
63EE085A1E075AAA00EE5F9A /* YKLayout+Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "YKLayout+Private.h"; path = "../../YKLayout+Private.h"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -77,6 +89,14 @@
files = (
13687D871DF87D2400E7C260 /* Foundation.framework in Frameworks */,
13687D851DF87D1E00E7C260 /* UIKit.framework in Frameworks */,
63EE08441E06ED3D00EE5F9A /* YogaKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
63EE08391E06ED3D00EE5F9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -86,9 +106,8 @@
13687D3A1DF8748300E7C260 = {
isa = PBXGroup;
children = (
13687D5D1DF8778F00E7C260 /* yoga */,
13687D641DF8778F00E7C260 /* YogaKit */,
13687D451DF8748400E7C260 /* YogaKitSample */,
63EE083E1E06ED3D00EE5F9A /* YogaKit */,
13687D441DF8748400E7C260 /* Products */,
13687D831DF87D1E00E7C260 /* Frameworks */,
);
@@ -98,6 +117,7 @@
isa = PBXGroup;
children = (
13687D431DF8748400E7C260 /* YogaKitSample.app */,
63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */,
);
name = Products;
sourceTree = "<group>";
@@ -109,6 +129,7 @@
13687D4A1DF8748400E7C260 /* AppDelegate.m */,
13687D4C1DF8748400E7C260 /* ViewController.h */,
13687D4D1DF8748400E7C260 /* ViewController.m */,
63EE08541E072EF800EE5F9A /* SwiftViewController.swift */,
13687D521DF8748400E7C260 /* Assets.xcassets */,
13687D571DF8748400E7C260 /* Info.plist */,
13687D461DF8748400E7C260 /* Supporting Files */,
@@ -127,7 +148,6 @@
13687D5D1DF8778F00E7C260 /* yoga */ = {
isa = PBXGroup;
children = (
13687D5E1DF8778F00E7C260 /* YGEnums.h */,
13687D5F1DF8778F00E7C260 /* YGMacros.h */,
13687D601DF8778F00E7C260 /* YGNodeList.c */,
13687D611DF8778F00E7C260 /* YGNodeList.h */,
@@ -135,17 +155,7 @@
13687D631DF8778F00E7C260 /* Yoga.h */,
);
name = yoga;
path = ../../yoga;
sourceTree = "<group>";
};
13687D641DF8778F00E7C260 /* YogaKit */ = {
isa = PBXGroup;
children = (
13687D691DF8778F00E7C260 /* UIView+Yoga.h */,
13687D6A1DF8778F00E7C260 /* UIView+Yoga.m */,
);
name = YogaKit;
path = ..;
path = ../../../yoga;
sourceTree = "<group>";
};
13687D831DF87D1E00E7C260 /* Frameworks */ = {
@@ -157,44 +167,101 @@
name = Frameworks;
sourceTree = "<group>";
};
63EE083E1E06ED3D00EE5F9A /* YogaKit */ = {
isa = PBXGroup;
children = (
13687D5D1DF8778F00E7C260 /* yoga */,
63EE083F1E06ED3D00EE5F9A /* YogaKit.h */,
63EE08521E06F3D100EE5F9A /* YKEnums.h */,
13687D691DF8778F00E7C260 /* UIView+YogaKit.h */,
13687D6A1DF8778F00E7C260 /* UIView+YogaKit.m */,
63EE08581E07591A00EE5F9A /* YKLayout.h */,
63EE085A1E075AAA00EE5F9A /* YKLayout+Private.h */,
63EE08561E07590C00EE5F9A /* YKLayout.m */,
63EE08401E06ED3D00EE5F9A /* Info.plist */,
);
path = YogaKit;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
63EE083A1E06ED3D00EE5F9A /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
63EE085B1E075B0B00EE5F9A /* YKLayout+Private.h in Headers */,
63EE08591E07598A00EE5F9A /* YKLayout.h in Headers */,
63EE08411E06ED3D00EE5F9A /* YogaKit.h in Headers */,
63EE08531E06F3D100EE5F9A /* YKEnums.h in Headers */,
63EE08511E06EECB00EE5F9A /* UIView+YogaKit.h in Headers */,
63EE084E1E06EECB00EE5F9A /* YGMacros.h in Headers */,
63EE084F1E06EECB00EE5F9A /* YGNodeList.h in Headers */,
63EE08501E06EECB00EE5F9A /* Yoga.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
13687D421DF8748300E7C260 /* YogaKitSample */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13687D5A1DF8748400E7C260 /* Build configuration list for PBXNativeTarget "YogaKitSample" */;
buildPhases = (
13687D771DF878A000E7C260 /* yoga */,
13687D7B1DF878CE00E7C260 /* YogaKit */,
13687D3F1DF8748300E7C260 /* Sources */,
13687D401DF8748300E7C260 /* Frameworks */,
13687D411DF8748300E7C260 /* Resources */,
63EE08491E06ED3D00EE5F9A /* Embed Frameworks */,
);
buildRules = (
);
dependencies = (
63EE08431E06ED3D00EE5F9A /* PBXTargetDependency */,
);
name = YogaKitSample;
productName = YogaKitSample;
productReference = 13687D431DF8748400E7C260 /* YogaKitSample.app */;
productType = "com.apple.product-type.application";
};
63EE083C1E06ED3D00EE5F9A /* YogaKit */ = {
isa = PBXNativeTarget;
buildConfigurationList = 63EE08481E06ED3D00EE5F9A /* Build configuration list for PBXNativeTarget "YogaKit" */;
buildPhases = (
63EE08381E06ED3D00EE5F9A /* Sources */,
63EE08391E06ED3D00EE5F9A /* Frameworks */,
63EE083A1E06ED3D00EE5F9A /* Headers */,
63EE083B1E06ED3D00EE5F9A /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = YogaKit;
productName = YogaKit;
productReference = 63EE083D1E06ED3D00EE5F9A /* YogaKit.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
13687D3B1DF8748300E7C260 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0810;
LastUpgradeCheck = 0820;
ORGANIZATIONNAME = facebook;
TargetAttributes = {
13687D421DF8748300E7C260 = {
CreatedOnToolsVersion = 8.1;
LastSwiftMigration = 0820;
ProvisioningStyle = Automatic;
};
63EE083C1E06ED3D00EE5F9A = {
CreatedOnToolsVersion = 8.2;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKitSample" */;
buildConfigurationList = 13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKit" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
@@ -207,6 +274,7 @@
projectDirPath = "";
projectRoot = "";
targets = (
63EE083C1E06ED3D00EE5F9A /* YogaKit */,
13687D421DF8748300E7C260 /* YogaKitSample */,
);
};
@@ -221,6 +289,13 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
63EE083B1E06ED3D00EE5F9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
@@ -228,17 +303,34 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13687D801DF87CEC00E7C260 /* UIView+Yoga.m in Sources */,
63EE08551E072EF800EE5F9A /* SwiftViewController.swift in Sources */,
13687D4E1DF8748400E7C260 /* ViewController.m in Sources */,
13687D4B1DF8748400E7C260 /* AppDelegate.m in Sources */,
13687D821DF87CF200E7C260 /* Yoga.c in Sources */,
13687D811DF87CF200E7C260 /* YGNodeList.c in Sources */,
13687D481DF8748400E7C260 /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
63EE08381E06ED3D00EE5F9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
63EE084A1E06EEB700EE5F9A /* YGNodeList.c in Sources */,
63EE084B1E06EEB700EE5F9A /* Yoga.c in Sources */,
63EE084C1E06EEB700EE5F9A /* UIView+YogaKit.m in Sources */,
63EE08571E07590C00EE5F9A /* YKLayout.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
63EE08431E06ED3D00EE5F9A /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 63EE083C1E06ED3D00EE5F9A /* YogaKit */;
targetProxy = 63EE08421E06ED3D00EE5F9A /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
13687D581DF8748400E7C260 /* Debug */ = {
isa = XCBuildConfiguration;
@@ -258,6 +350,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -305,6 +398,7 @@
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_SUSPICIOUS_MOVES = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -332,10 +426,13 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
INFOPLIST_FILE = YogaKitSample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
};
name = Debug;
};
@@ -343,17 +440,65 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
INFOPLIST_FILE = YogaKitSample/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
};
name = Release;
};
63EE08461E06ED3D00EE5F9A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = YogaKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Debug;
};
63EE08471E06ED3D00EE5F9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CODE_SIGN_IDENTITY = "";
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
INFOPLIST_FILE = YogaKit/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 10.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKit;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKitSample" */ = {
13687D3E1DF8748300E7C260 /* Build configuration list for PBXProject "YogaKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13687D581DF8748400E7C260 /* Debug */,
@@ -369,6 +514,16 @@
13687D5C1DF8748400E7C260 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
63EE08481E06ED3D00EE5F9A /* Build configuration list for PBXNativeTarget "YogaKit" */ = {
isa = XCConfigurationList;
buildConfigurations = (
63EE08461E06ED3D00EE5F9A /* Debug */,
63EE08471E06ED3D00EE5F9A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};

View File

@@ -2,6 +2,6 @@
<Workspace
version = "1.0">
<FileRef
location = "self:YogaKitSample.xcodeproj">
location = "self:/Users/david/Projects/yoga/YogaKit/YogaKit/YogaKit.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0810"
LastUpgradeVersion = "0820"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@@ -14,10 +14,10 @@
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
BlueprintIdentifier = "63EE083C1E06ED3D00EE5F9A"
BuildableName = "YogaKit.framework"
BlueprintName = "YogaKit"
ReferencedContainer = "container:YogaKit.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -29,15 +29,6 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
@@ -51,16 +42,15 @@
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
BlueprintIdentifier = "63EE083C1E06ED3D00EE5F9A"
BuildableName = "YogaKit.framework"
BlueprintName = "YogaKit"
ReferencedContainer = "container:YogaKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
@@ -70,16 +60,15 @@
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13687D421DF8748300E7C260"
BuildableName = "YogaKitSample.app"
BlueprintName = "YogaKitSample"
ReferencedContainer = "container:YogaKitSample.xcodeproj">
BlueprintIdentifier = "63EE083C1E06ED3D00EE5F9A"
BuildableName = "YogaKit.framework"
BlueprintName = "YogaKit"
ReferencedContainer = "container:YogaKit.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">

View File

@@ -0,0 +1,24 @@
<?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>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>

View File

@@ -0,0 +1,18 @@
//
// YogaKit.h
// YogaKit
//
// Created by David Hart on 18.12.16.
// Copyright © 2016 facebook. All rights reserved.
//
#import <UIKit/UIKit.h>
//! Project version number for YogaKit.
FOUNDATION_EXPORT double YogaKitVersionNumber;
//! Project version string for YogaKit.
FOUNDATION_EXPORT const unsigned char YogaKitVersionString[];
#import <YogaKit/UIView+YogaKit.h>
#import <YogaKit/YKEnums.h>

View File

@@ -0,0 +1,41 @@
//
// SwiftViewController.swift
// YogaKit
//
// Created by David Hart on 18.12.16.
// Copyright © 2016 facebook. All rights reserved.
//
import UIKit
import YogaKit
class SwiftViewController : UIViewController {
override func viewDidLoad() {
let root = view!
root.backgroundColor = .red
root.layout.isEnabled = true
root.layout.width = view.bounds.size.width
root.layout.height = view.bounds.size.height
root.layout.alignItems = .center
root.layout.justifyContent = .center
let child1 = UIView()
child1.backgroundColor = .blue
child1.layout.isEnabled = true
child1.layout.width = 100
child1.layout.height = 100
let child2 = UIView()
child2.backgroundColor = .green
child2.frame = CGRect(origin: .zero, size: CGSize(width: 200, height: 100))
let child3 = UIView()
child3.backgroundColor = .yellow
child3.frame = CGRect(origin: .zero, size: CGSize(width: 100, height: 100))
child2.addSubview(child3)
root.addSubview(child1)
root.addSubview(child2)
root.layout.apply()
}
}

View File

@@ -10,6 +10,5 @@
@interface ViewController : UIViewController
@end

View File

@@ -7,8 +7,7 @@
*/
#import "ViewController.h"
#import <YogaKit/UIView+Yoga.h>
#import <YogaKit/YogaKit.h>
@interface ViewController ()
@@ -20,17 +19,17 @@
{
UIView *root = self.view;
root.backgroundColor = [UIColor redColor];
[root yg_setUsesYoga:YES];
[root yg_setWidth:self.view.bounds.size.width];
[root yg_setHeight:self.view.bounds.size.height];
[root yg_setAlignItems:YGAlignCenter];
[root yg_setJustifyContent:YGJustifyCenter];
root.layout.isEnabled = YES;
root.layout.width = self.view.bounds.size.width;
root.layout.height = self.view.bounds.size.height;
root.layout.alignItems = YKAlignCenter;
root.layout.justifyContent = YKJustifyCenter;
UIView *child1 = [UIView new];
child1.backgroundColor = [UIColor blueColor];
[child1 yg_setUsesYoga:YES];
[child1 yg_setWidth:100];
[child1 yg_setHeight:100];
child1.layout.isEnabled = YES;
child1.layout.width = 100;
child1.layout.height = 100;
UIView *child2 = [UIView new];
child2.backgroundColor = [UIColor greenColor];
@@ -53,7 +52,7 @@
[child2 addSubview:child3];
[root addSubview:child1];
[root addSubview:child2];
[root yg_applyLayout];
[root.layout apply];
}

View File

@@ -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>

View File

@@ -89,6 +89,21 @@ ENUMS = {
],
}
OBJC_ENUMS = {
'Direction': [
'Inherit',
'LeftToRight',
'RightToLeft',
],
'Edge': None,
'MeasureMode': None,
'PrintOptions': None,
'Dimension': None,
'LogLevel': None,
'Overflow': None,
'ExperimentalFeature': None
}
LICENSE = """/**
* Copyright (c) 2014-present, Facebook, Inc.
* All rights reserved.
@@ -187,3 +202,19 @@ for name, values in ENUMS.items():
f.write(' %s,\n' % value)
f.write(' }\n')
f.write('}\n')
# write out objc files
with open(root + '/YogaKit/YKEnums.h', 'w') as f:
objc_enums = ENUMS
objc_enums.update(OBJC_ENUMS)
f.write(LICENSE)
for name, values in objc_enums.items():
if values is not None:
f.write('typedef NS_ENUM(NSInteger, YK%s) {\n' % name)
for value in values:
if isinstance(value, tuple):
f.write(' YK%s%s = %d,\n' % (name, value[0], value[1]))
else:
f.write(' YK%s%s,\n' % (name, value))
f.write('} NS_SWIFT_NAME(%s);\n' % name)
f.write('\n')