Rename uikit/CSSLayout to CSSLayoutKit.
Summary: When trying to integrate this into an Xcode project that already included CSSLayout.[c|h], we were getting a linker error. Upon digging in, I found out that Xcode was becoming confused because the imports of the uikit library and the c library are both `#import <CSSLayout/CSSLayout.h>`. So, it needed a new name. Reviewed By: emilsjolander Differential Revision: D4162621 fbshipit-source-id: b5f7624eb29f1b9eaebbed5104ec9ea8a12ad2e5
This commit is contained in:
committed by
Facebook Github Bot
parent
3e2c13f418
commit
70e01a4476
41
CSSLayoutKit/BUCK
Normal file
41
CSSLayoutKit/BUCK
Normal file
@@ -0,0 +1,41 @@
|
||||
# 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.
|
||||
|
||||
include_defs('//CSSLAYOUT_DEFS')
|
||||
|
||||
UIKIT_CSSLAYOUT_COMPILER_FLAGS = ['-fobjc-arc']
|
||||
|
||||
apple_library(
|
||||
name = 'CSSLayoutKit',
|
||||
compiler_flags = UIKIT_CSSLAYOUT_COMPILER_FLAGS,
|
||||
tests = [':CSSLayoutKitTests'],
|
||||
srcs = glob(['*.m']),
|
||||
exported_headers = glob(['*.h']),
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/Foundation.framework',
|
||||
'$SDKROOT/System/Library/Frameworks/UIKit.framework',
|
||||
],
|
||||
deps = [
|
||||
csslayout_dep(':CSSLayout'),
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
||||
|
||||
apple_test(
|
||||
name = 'CSSLayoutKitTests',
|
||||
compiler_flags = UIKIT_CSSLAYOUT_COMPILER_FLAGS,
|
||||
info_plist = 'Tests/Info.plist',
|
||||
srcs = glob(['Tests/**/*.m']),
|
||||
frameworks = [
|
||||
'$SDKROOT/System/Library/Frameworks/CoreGraphics.framework',
|
||||
'$PLATFORM_DIR/Developer/Library/Frameworks/XCTest.framework',
|
||||
],
|
||||
deps = [
|
||||
':CSSLayoutKit',
|
||||
],
|
||||
visibility = ['PUBLIC'],
|
||||
)
|
110
CSSLayoutKit/Tests/CSSLayoutTests.m
Normal file
110
CSSLayoutKit/Tests/CSSLayoutTests.m
Normal file
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* 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 <XCTest/XCTest.h>
|
||||
|
||||
#import "UIView+CSSLayout.h"
|
||||
|
||||
@interface CSSLayoutTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation CSSLayoutTests
|
||||
|
||||
- (void)testNodesAreDeallocedWithSingleView
|
||||
{
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[view css_setFlexBasis:1];
|
||||
XCTAssertEqual(1, CSSNodeGetInstanceCount());
|
||||
view = nil;
|
||||
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
}
|
||||
|
||||
- (void)testNodesAreDeallocedCascade
|
||||
{
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[view css_setFlexBasis:1];
|
||||
|
||||
for (int i=0; i<10; i++) {
|
||||
UIView *subview = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[subview css_setFlexBasis:1];
|
||||
[view addSubview:subview];
|
||||
}
|
||||
XCTAssertEqual(11, CSSNodeGetInstanceCount());
|
||||
view = nil;
|
||||
|
||||
XCTAssertEqual(0, CSSNodeGetInstanceCount());
|
||||
}
|
||||
|
||||
- (void)testUsesFlexbox
|
||||
{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
XCTAssertFalse([view css_usesFlexbox]);
|
||||
|
||||
[view css_setUsesFlexbox:YES];
|
||||
XCTAssertTrue([view css_usesFlexbox]);
|
||||
|
||||
[view css_setUsesFlexbox:NO];
|
||||
XCTAssertFalse([view css_usesFlexbox]);
|
||||
}
|
||||
|
||||
- (void)testSizeThatFitsAsserts
|
||||
{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
XCTAssertThrows([view css_sizeThatFits:CGSizeZero]);
|
||||
|
||||
dispatch_sync(dispatch_queue_create("com.facebook.CSSLayout.testing", DISPATCH_QUEUE_SERIAL), ^(void){
|
||||
XCTAssertThrows([view css_sizeThatFits:CGSizeZero]);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)testSizeThatFitsSmoke
|
||||
{
|
||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
[view css_setUsesFlexbox:YES];
|
||||
|
||||
const CGSize constrainedSize = CGSizeMake(50, 50);
|
||||
const CGSize actualSize = [view css_sizeThatFits:constrainedSize];
|
||||
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
|
22
CSSLayoutKit/Tests/Info.plist
Normal file
22
CSSLayoutKit/Tests/Info.plist
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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>com.facebook.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
</dict>
|
||||
</plist>
|
51
CSSLayoutKit/UIView+CSSLayout.h
Normal file
51
CSSLayoutKit/UIView+CSSLayout.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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 <CSSLayout/CSSLayout.h>
|
||||
|
||||
@interface UIView (CSSLayout)
|
||||
|
||||
- (void)css_setUsesFlexbox:(BOOL)enabled;
|
||||
- (BOOL)css_usesFlexbox;
|
||||
|
||||
- (void)css_setDirection:(CSSDirection)direction;
|
||||
- (void)css_setFlexDirection:(CSSFlexDirection)flexDirection;
|
||||
- (void)css_setJustifyContent:(CSSJustify)justifyContent;
|
||||
- (void)css_setAlignContent:(CSSAlign)alignContent;
|
||||
- (void)css_setAlignItems:(CSSAlign)alignItems;
|
||||
- (void)css_setAlignSelf:(CSSAlign)alignSelf;
|
||||
- (void)css_setPositionType:(CSSPositionType)positionType;
|
||||
- (void)css_setFlexWrap:(CSSWrapType)flexWrap;
|
||||
|
||||
- (void)css_setFlexGrow:(CGFloat)flexGrow;
|
||||
- (void)css_setFlexShrink:(CGFloat)flexShrink;
|
||||
- (void)css_setFlexBasis:(CGFloat)flexBasis;
|
||||
|
||||
- (void)css_setPosition:(CGFloat)position forEdge:(CSSEdge)edge;
|
||||
- (void)css_setMargin:(CGFloat)margin forEdge:(CSSEdge)edge;
|
||||
- (void)css_setPadding:(CGFloat)padding forEdge:(CSSEdge)edge;
|
||||
|
||||
- (void)css_setWidth:(CGFloat)width;
|
||||
- (void)css_setHeight:(CGFloat)height;
|
||||
- (void)css_setMinWidth:(CGFloat)minWidth;
|
||||
- (void)css_setMinHeight:(CGFloat)minHeight;
|
||||
- (void)css_setMaxWidth:(CGFloat)maxWidth;
|
||||
- (void)css_setMaxHeight:(CGFloat)maxHeight;
|
||||
|
||||
// Get the resolved direction of this node. This won't be CSSDirectionInherit
|
||||
- (CSSDirection)css_resolvedDirection;
|
||||
|
||||
//! @abstract Perform a layout calculation and update the frames of the views in the hierarchy with th results
|
||||
- (void)css_applyLayout;
|
||||
|
||||
//! @abstract Compute the size of a layout with a constrained size.
|
||||
- (CGSize)css_sizeThatFits:(CGSize)constrainedSize;
|
||||
|
||||
@end
|
311
CSSLayoutKit/UIView+CSSLayout.m
Normal file
311
CSSLayoutKit/UIView+CSSLayout.m
Normal file
@@ -0,0 +1,311 @@
|
||||
/**
|
||||
* 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+CSSLayout.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@interface CSSNodeBridge : NSObject
|
||||
@property (nonatomic, assign, readonly) CSSNodeRef cnode;
|
||||
@end
|
||||
|
||||
@implementation CSSNodeBridge
|
||||
- (instancetype)init
|
||||
{
|
||||
if ([super init]) {
|
||||
_cnode = CSSNodeNew();
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
CSSNodeFree(_cnode);
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation UIView (CSSLayout)
|
||||
|
||||
- (CSSNodeRef)cssNode
|
||||
{
|
||||
CSSNodeBridge *node = objc_getAssociatedObject(self, @selector(cssNode));
|
||||
if (!node) {
|
||||
node = [CSSNodeBridge new];
|
||||
CSSNodeSetContext(node.cnode, (__bridge void *) self);
|
||||
objc_setAssociatedObject(self, @selector(cssNode), node, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
return node.cnode;
|
||||
}
|
||||
|
||||
- (void)css_setUsesFlexbox:(BOOL)enabled
|
||||
{
|
||||
objc_setAssociatedObject(
|
||||
self,
|
||||
@selector(css_usesFlexbox),
|
||||
@(enabled),
|
||||
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (BOOL)css_usesFlexbox
|
||||
{
|
||||
NSNumber *usesFlexbox = objc_getAssociatedObject(self, @selector(css_usesFlexbox));
|
||||
return [usesFlexbox boolValue];
|
||||
}
|
||||
|
||||
- (void)css_setDirection:(CSSDirection)direction
|
||||
{
|
||||
CSSNodeStyleSetDirection([self cssNode], direction);
|
||||
}
|
||||
|
||||
- (void)css_setFlexDirection:(CSSFlexDirection)flexDirection
|
||||
{
|
||||
CSSNodeStyleSetFlexDirection([self cssNode], flexDirection);
|
||||
}
|
||||
|
||||
- (void)css_setJustifyContent:(CSSJustify)justifyContent
|
||||
{
|
||||
CSSNodeStyleSetJustifyContent([self cssNode], justifyContent);
|
||||
}
|
||||
|
||||
- (void)css_setAlignContent:(CSSAlign)alignContent
|
||||
{
|
||||
CSSNodeStyleSetAlignContent([self cssNode], alignContent);
|
||||
}
|
||||
|
||||
- (void)css_setAlignItems:(CSSAlign)alignItems
|
||||
{
|
||||
CSSNodeStyleSetAlignItems([self cssNode], alignItems);
|
||||
}
|
||||
|
||||
- (void)css_setAlignSelf:(CSSAlign)alignSelf
|
||||
{
|
||||
CSSNodeStyleSetAlignSelf([self cssNode], alignSelf);
|
||||
}
|
||||
|
||||
- (void)css_setPositionType:(CSSPositionType)positionType
|
||||
{
|
||||
CSSNodeStyleSetPositionType([self cssNode], positionType);
|
||||
}
|
||||
|
||||
- (void)css_setFlexWrap:(CSSWrapType)flexWrap
|
||||
{
|
||||
CSSNodeStyleSetFlexWrap([self cssNode], flexWrap);
|
||||
}
|
||||
|
||||
- (void)css_setFlexGrow:(CGFloat)flexGrow
|
||||
{
|
||||
CSSNodeStyleSetFlexGrow([self cssNode], flexGrow);
|
||||
}
|
||||
|
||||
- (void)css_setFlexShrink:(CGFloat)flexShrink
|
||||
{
|
||||
CSSNodeStyleSetFlexShrink([self cssNode], flexShrink);
|
||||
}
|
||||
|
||||
- (void)css_setFlexBasis:(CGFloat)flexBasis
|
||||
{
|
||||
CSSNodeStyleSetFlexBasis([self cssNode], flexBasis);
|
||||
}
|
||||
|
||||
- (void)css_setPosition:(CGFloat)position forEdge:(CSSEdge)edge
|
||||
{
|
||||
CSSNodeStyleSetPosition([self cssNode], edge, position);
|
||||
}
|
||||
|
||||
- (void)css_setMargin:(CGFloat)margin forEdge:(CSSEdge)edge
|
||||
{
|
||||
CSSNodeStyleSetMargin([self cssNode], edge, margin);
|
||||
}
|
||||
|
||||
- (void)css_setPadding:(CGFloat)padding forEdge:(CSSEdge)edge
|
||||
{
|
||||
CSSNodeStyleSetPadding([self cssNode], edge, padding);
|
||||
}
|
||||
|
||||
- (void)css_setWidth:(CGFloat)width
|
||||
{
|
||||
CSSNodeStyleSetWidth([self cssNode], width);
|
||||
}
|
||||
|
||||
- (void)css_setHeight:(CGFloat)height
|
||||
{
|
||||
CSSNodeStyleSetHeight([self cssNode], height);
|
||||
}
|
||||
|
||||
- (void)css_setMinWidth:(CGFloat)minWidth
|
||||
{
|
||||
CSSNodeStyleSetMinWidth([self cssNode], minWidth);
|
||||
}
|
||||
|
||||
- (void)css_setMinHeight:(CGFloat)minHeight
|
||||
{
|
||||
CSSNodeStyleSetMinHeight([self cssNode], minHeight);
|
||||
}
|
||||
|
||||
- (void)css_setMaxWidth:(CGFloat)maxWidth
|
||||
{
|
||||
CSSNodeStyleSetMaxWidth([self cssNode], maxWidth);
|
||||
}
|
||||
|
||||
- (void)css_setMaxHeight:(CGFloat)maxHeight
|
||||
{
|
||||
CSSNodeStyleSetMaxHeight([self cssNode], maxHeight);
|
||||
}
|
||||
|
||||
- (CSSDirection)css_resolvedDirection
|
||||
{
|
||||
return CSSNodeLayoutGetDirection([self cssNode]);
|
||||
}
|
||||
|
||||
- (CGSize)css_sizeThatFits:(CGSize)constrainedSize
|
||||
{
|
||||
NSAssert([NSThread isMainThread], @"CSS Layout calculation must be done on main.");
|
||||
NSAssert([self css_usesFlexbox], @"CSS Layout is not enabled for this view.");
|
||||
|
||||
_attachNodesRecursive(self);
|
||||
|
||||
const CSSNodeRef node = [self cssNode];
|
||||
CSSNodeCalculateLayout(
|
||||
node,
|
||||
constrainedSize.width,
|
||||
constrainedSize.height,
|
||||
CSSNodeStyleGetDirection(node));
|
||||
|
||||
return (CGSize) {
|
||||
.width = CSSNodeLayoutGetWidth(node),
|
||||
.height = CSSNodeLayoutGetHeight(node),
|
||||
};
|
||||
}
|
||||
|
||||
- (void)css_applyLayout
|
||||
{
|
||||
[self css_sizeThatFits:self.bounds.size];
|
||||
_updateFrameRecursive(self);
|
||||
}
|
||||
|
||||
#pragma mark - Private
|
||||
|
||||
static CSSSize _measure(
|
||||
CSSNodeRef node,
|
||||
float width,
|
||||
CSSMeasureMode widthMode,
|
||||
float height,
|
||||
CSSMeasureMode heightMode)
|
||||
{
|
||||
const CGFloat constrainedWidth = (widthMode == CSSMeasureModeUndefined) ? CGFLOAT_MAX : width;
|
||||
const CGFloat constrainedHeight = (heightMode == CSSMeasureModeUndefined) ? CGFLOAT_MAX: height;
|
||||
|
||||
UIView *view = (__bridge UIView*) CSSNodeGetContext(node);
|
||||
const CGSize sizeThatFits = [view sizeThatFits:(CGSize) {
|
||||
.width = constrainedWidth,
|
||||
.height = constrainedHeight,
|
||||
}];
|
||||
|
||||
return (CSSSize) {
|
||||
.width = _sanitizeMeasurement(constrainedWidth, sizeThatFits.width, widthMode),
|
||||
.height = _sanitizeMeasurement(constrainedHeight, sizeThatFits.height, heightMode),
|
||||
};
|
||||
}
|
||||
|
||||
static CGFloat _sanitizeMeasurement(
|
||||
CGFloat constrainedSize,
|
||||
CGFloat measuredSize,
|
||||
CSSMeasureMode measureMode)
|
||||
{
|
||||
CGFloat result;
|
||||
if (measureMode == CSSMeasureModeExactly) {
|
||||
result = constrainedSize;
|
||||
} else if (measureMode == CSSMeasureModeAtMost) {
|
||||
result = MIN(constrainedSize, measuredSize);
|
||||
} else {
|
||||
result = measuredSize;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void _attachNodesRecursive(UIView *view) {
|
||||
CSSNodeRef node = [view cssNode];
|
||||
const BOOL usesFlexbox = [view css_usesFlexbox];
|
||||
const BOOL isLeaf = !usesFlexbox || view.subviews.count == 0;
|
||||
|
||||
// Only leaf nodes should have a measure function
|
||||
if (isLeaf) {
|
||||
CSSNodeSetMeasureFunc(node, _measure);
|
||||
|
||||
// Clear any children
|
||||
while (CSSNodeChildCount(node) > 0) {
|
||||
CSSNodeRemoveChild(node, CSSNodeGetChild(node, 0));
|
||||
}
|
||||
} else {
|
||||
CSSNodeSetMeasureFunc(node, NULL);
|
||||
|
||||
// Add any children which were added since the last call to css_applyLayout
|
||||
for (NSUInteger i = 0; i < view.subviews.count; i++) {
|
||||
CSSNodeRef childNode = [view.subviews[i] cssNode];
|
||||
if (CSSNodeChildCount(node) < i + 1 || CSSNodeGetChild(node, i) != childNode) {
|
||||
CSSNodeInsertChild(node, childNode, i);
|
||||
}
|
||||
_attachNodesRecursive(view.subviews[i]);
|
||||
}
|
||||
|
||||
// Remove any children which were removed since the last call to css_applyLayout
|
||||
while (view.subviews.count < CSSNodeChildCount(node)) {
|
||||
CSSNodeRemoveChild(node, CSSNodeGetChild(node, CSSNodeChildCount(node) - 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
NSCAssert([NSThread isMainThread], @"Framesetting should only be done on the main thread.");
|
||||
CSSNodeRef node = [view cssNode];
|
||||
|
||||
const CGPoint topLeft = {
|
||||
CSSNodeLayoutGetLeft(node),
|
||||
CSSNodeLayoutGetTop(node),
|
||||
};
|
||||
|
||||
const CGPoint bottomRight = {
|
||||
topLeft.x + CSSNodeLayoutGetWidth(node),
|
||||
topLeft.y + CSSNodeLayoutGetHeight(node),
|
||||
};
|
||||
|
||||
view.frame = (CGRect) {
|
||||
.origin = {
|
||||
.x = _roundPixelValue(topLeft.x),
|
||||
.y = _roundPixelValue(topLeft.y),
|
||||
},
|
||||
.size = {
|
||||
.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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Reference in New Issue
Block a user