[YogaKit] support macOS, tvOS, Carthage; auto apply layout like AutoLayout. #1026

Closed
cntrump wants to merge 38 commits from yogakit_autoapplylayout_patch into main
13 changed files with 200 additions and 76 deletions
Showing only changes of commit 14f7e8bb2c - Show all commits

View File

@@ -5,7 +5,7 @@
Pod::Spec.new do |spec| Pod::Spec.new do |spec|
spec.name = 'Yoga' spec.name = 'Yoga'
spec.version = '1.14.0' spec.version = '1.14.1'
spec.license = { :type => 'MIT', :file => "LICENSE" } spec.license = { :type => 'MIT', :file => "LICENSE" }
spec.homepage = 'https://yogalayout.com/' spec.homepage = 'https://yogalayout.com/'
spec.documentation_url = 'https://yogalayout.com/docs' spec.documentation_url = 'https://yogalayout.com/docs'
@@ -34,5 +34,5 @@ Pod::Spec.new do |spec|
] ]
spec.source_files = 'yoga/**/*.{c,h,cpp}' spec.source_files = 'yoga/**/*.{c,h,cpp}'
spec.public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGNode,YGStyle,YGValue}.h' spec.public_header_files = 'yoga/{Yoga,YGEnums,YGMacros,YGNode,YGStyle,YGValue}.h'
spec.static_framework = true
end end

View File

@@ -23,7 +23,7 @@ podspec = Pod::Spec.new do |spec|
spec.ios.deployment_target = '8.0' spec.ios.deployment_target = '8.0'
spec.ios.frameworks = 'UIKit' spec.ios.frameworks = 'UIKit'
spec.module_name = 'YogaKit' spec.module_name = 'YogaKit'
spec.dependency 'Yoga', '~> 1.14' spec.dependency 'Yoga', '~> 1.14.1'
# Fixes the bug related the xcode 11 not able to find swift related frameworks. # Fixes the bug related the xcode 11 not able to find swift related frameworks.
# https://github.com/Carthage/Carthage/issues/2825 # https://github.com/Carthage/Carthage/issues/2825
# https://twitter.com/krzyzanowskim/status/1151549874653081601?s=21 # https://twitter.com/krzyzanowskim/status/1151549874653081601?s=21
@@ -32,6 +32,7 @@ podspec = Pod::Spec.new do |spec|
spec.public_header_files = 'YogaKit/Source/{YGLayout,UIView+Yoga}.h' spec.public_header_files = 'YogaKit/Source/{YGLayout,UIView+Yoga}.h'
spec.private_header_files = 'YogaKit/Source/YGLayout+Private.h' spec.private_header_files = 'YogaKit/Source/YGLayout+Private.h'
spec.swift_version = '5.1' spec.swift_version = '5.1'
spec.static_framework = true
end end
# See https://github.com/facebook/yoga/pull/366 # See https://github.com/facebook/yoga/pull/366

View File

@@ -34,4 +34,9 @@ typedef void (^YGLayoutConfigurationBlock)(YGLayout* layout);
@end @end
@interface UIView (YogaKitAutoApplyLayout)
@end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@@ -35,3 +35,88 @@ static const void* kYGYogaAssociatedKey = &kYGYogaAssociatedKey;
} }
@end @end
static const void* kYGBoundsSizeAssociatedKey = &kYGBoundsSizeAssociatedKey;
static void YogaSwizzleInstanceMethod(Class cls, SEL originalSelector, SEL swizzledSelector);
@implementation UIView (YogaKitAutoApplyLayout)
+ (void)load {
static dispatch_once_t onceToken = 0;
dispatch_once(&onceToken, ^{
YogaSwizzleInstanceMethod(self, @selector(initWithFrame:), @selector(_yoga_initWithFrame:));
YogaSwizzleInstanceMethod(self, @selector(setFrame:), @selector(_yoga_setFrame:));
YogaSwizzleInstanceMethod(self, @selector(setBounds:), @selector(_yoga_setBounds:));
});
}
- (CGSize)_yoga_boundsSize {
NSValue *value = (NSValue *)objc_getAssociatedObject(self, kYGBoundsSizeAssociatedKey);
return value ? value.CGSizeValue : CGSizeMake(YGUndefined, YGUndefined);
}
- (void)set_yoga_boundsSize:(CGSize)size {
objc_setAssociatedObject(self,
kYGBoundsSizeAssociatedKey,
[NSValue valueWithCGSize:size],
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (instancetype)_yoga_initWithFrame:(CGRect)frame {
id _self = [self _yoga_initWithFrame:frame];
if (_self) {
[self _yoga_applyLayout];
}
return _self;
}
- (void)_yoga_setFrame:(CGRect)frame {
[self _yoga_setFrame:frame];
[self _yoga_applyLayout];
}
- (void)_yoga_setBounds:(CGRect)bounds {
[self _yoga_setBounds:bounds];
[self _yoga_applyLayout];
}
- (void)_yoga_applyLayout {
if (self.isYogaEnabled && self.yoga.isEnabled) {
CGSize size = self.bounds.size;
CGSize prev = self._yoga_boundsSize;
if (!CGSizeEqualToSize(size, prev)) {
self._yoga_boundsSize = size;
[self.yoga applyLayoutPreservingOrigin:YES];
}
}
}
@end
static void YogaSwizzleInstanceMethod(Class cls, SEL originalSelector, SEL swizzledSelector) {
if (!cls || !originalSelector || !swizzledSelector) {
return;
}
Method originalMethod = class_getInstanceMethod(cls, originalSelector);
Method swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
if (!originalMethod || !swizzledMethod) {
return;
}
IMP swizzledIMP = method_getImplementation(swizzledMethod);
if (class_addMethod(cls, originalSelector, swizzledIMP, method_getTypeEncoding(swizzledMethod))) {
class_replaceMethod(cls,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}

View File

@@ -162,6 +162,7 @@ static YGConfigRef globalConfig;
@property(nonatomic, weak, readonly) UIView* view; @property(nonatomic, weak, readonly) UIView* view;
@property(nonatomic, assign, readonly) BOOL isUIView; @property(nonatomic, assign, readonly) BOOL isUIView;
@property(nonatomic, assign) BOOL isApplingLayout;
@end @end
@@ -292,11 +293,19 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio)
} }
- (void)applyLayout { - (void)applyLayout {
if (self.isApplingLayout) {
return;
}
[self calculateLayoutWithSize:self.view.bounds.size]; [self calculateLayoutWithSize:self.view.bounds.size];
YGApplyLayoutToViewHierarchy(self.view, NO); YGApplyLayoutToViewHierarchy(self.view, NO);
} }
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin { - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin {
if (self.isApplingLayout) {
return;
}
[self calculateLayoutWithSize:self.view.bounds.size]; [self calculateLayoutWithSize:self.view.bounds.size];
YGApplyLayoutToViewHierarchy(self.view, preserveOrigin); YGApplyLayoutToViewHierarchy(self.view, preserveOrigin);
} }
@@ -304,6 +313,10 @@ YG_PROPERTY(CGFloat, aspectRatio, AspectRatio)
- (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin - (void)applyLayoutPreservingOrigin:(BOOL)preserveOrigin
dimensionFlexibility: dimensionFlexibility:
(YGDimensionFlexibility)dimensionFlexibility { (YGDimensionFlexibility)dimensionFlexibility {
if (self.isApplingLayout) {
return;
}
CGSize size = self.view.bounds.size; CGSize size = self.view.bounds.size;
if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) { if (dimensionFlexibility & YGDimensionFlexibilityFlexibleWidth) {
size.width = YGUndefined; size.width = YGUndefined;
@@ -463,12 +476,22 @@ static void YGApplyLayoutToViewHierarchy(UIView* view, BOOL preserveOrigin) {
[NSThread isMainThread], [NSThread isMainThread],
@"Framesetting should only be done on the main thread."); @"Framesetting should only be done on the main thread.");
if (!view.isYogaEnabled || !view.yoga.isEnabled) {
return;
}
const YGLayout* yoga = view.yoga; const YGLayout* yoga = view.yoga;
if (yoga.isApplingLayout) {
return;
}
if (!yoga.isIncludedInLayout) { if (!yoga.isIncludedInLayout) {
return; return;
} }
yoga.isApplingLayout = YES;
YGNodeRef node = yoga.node; YGNodeRef node = yoga.node;
const CGPoint topLeft = { const CGPoint topLeft = {
YGNodeLayoutGetLeft(node), YGNodeLayoutGetLeft(node),
@@ -481,7 +504,7 @@ static void YGApplyLayoutToViewHierarchy(UIView* view, BOOL preserveOrigin) {
}; };
const CGPoint origin = preserveOrigin ? view.frame.origin : CGPointZero; const CGPoint origin = preserveOrigin ? view.frame.origin : CGPointZero;
view.frame = (CGRect){ CGRect frame = (CGRect){
.origin = .origin =
{ {
.x = YGRoundPixelValue(topLeft.x + origin.x), .x = YGRoundPixelValue(topLeft.x + origin.x),
@@ -489,18 +512,31 @@ static void YGApplyLayoutToViewHierarchy(UIView* view, BOOL preserveOrigin) {
}, },
.size = .size =
{ {
.width = YGRoundPixelValue(bottomRight.x) - .width = MAX(YGRoundPixelValue(bottomRight.x) -
YGRoundPixelValue(topLeft.x), YGRoundPixelValue(topLeft.x), 0),
.height = YGRoundPixelValue(bottomRight.y) - .height = MAX(YGRoundPixelValue(bottomRight.y) -
YGRoundPixelValue(topLeft.y), YGRoundPixelValue(topLeft.y), 0),
}, },
}; };
// use bounds/center and not frame if non-identity transform.
view.bounds = (CGRect) {
.origin = view.bounds.origin,
.size = frame.size
};
view.center = (CGPoint) {
.x = YGRoundPixelValue(CGRectGetMinX(frame) + CGRectGetWidth(frame) * 0.5),
.y = YGRoundPixelValue(CGRectGetMinY(frame) + CGRectGetHeight(frame) * 0.5)
};
if (!yoga.isLeaf) { if (!yoga.isLeaf) {
for (NSUInteger i = 0; i < view.subviews.count; i++) { for (NSUInteger i = 0; i < view.subviews.count; i++) {
YGApplyLayoutToViewHierarchy(view.subviews[i], NO); YGApplyLayoutToViewHierarchy(view.subviews[i], NO);
} }
} }
yoga.isApplingLayout = NO;
} }
@end @end

View File

@@ -1,6 +1,8 @@
platform :ios, '9.0'
use_frameworks! use_frameworks!
target 'YogaKitSample' do target 'YogaKitSample' do
pod 'Yoga', :path => '../../Yoga.podspec'
pod 'YogaKit', :path => '../../YogaKit.podspec' pod 'YogaKit', :path => '../../YogaKit.podspec'
pod 'IGListKit', '~> 2.1.0' pod 'IGListKit', '~> 4.0.0'
end end

View File

@@ -1,26 +1,33 @@
PODS: PODS:
- IGListKit (2.1.0): - IGListDiffKit (4.0.0)
- IGListKit/Default (= 2.1.0) - IGListKit (4.0.0):
- IGListKit/Default (2.1.0): - IGListDiffKit (= 4.0.0)
- IGListKit/Diffing - Yoga (1.14.1)
- IGListKit/Diffing (2.1.0) - YogaKit (1.18.1):
- Yoga (1.7.0) - Yoga (~> 1.14.1)
- YogaKit (1.7.0):
- Yoga (~> 1.7)
DEPENDENCIES: DEPENDENCIES:
- IGListKit (~> 2.1.0) - IGListKit (~> 4.0.0)
- Yoga (from `../../Yoga.podspec`)
- YogaKit (from `../../YogaKit.podspec`) - YogaKit (from `../../YogaKit.podspec`)
SPEC REPOS:
trunk:
- IGListDiffKit
- IGListKit
EXTERNAL SOURCES: EXTERNAL SOURCES:
Yoga:
:path: "../../Yoga.podspec"
YogaKit: YogaKit:
:path: ../../YogaKit.podspec :path: "../../YogaKit.podspec"
SPEC CHECKSUMS: SPEC CHECKSUMS:
IGListKit: b826c68ef7a4ae1626c09d4d3e1ea7a169e6c36e IGListDiffKit: 665d6cf43ce726e676013db9c7d6c4294259b6b2
Yoga: 2ed1d7accfef3610a67f58c0cf101a0662137f2c IGListKit: fd5a5d21935298f5849fa49d426843cff97b77c7
YogaKit: 31576530e8fcae3175469719ec3212397403330b Yoga: 1b62f19e549f5e174fc935ba76a47a8d9b60211e
YogaKit: befe87ed72becf4125f290a33af021e9992712c7
PODFILE CHECKSUM: 216f8e7127767709e0e43f3711208d238fa5c404 PODFILE CHECKSUM: 31f0f3ccdee77adc2f4b58b4772186c206fd1446
COCOAPODS: 1.1.1 COCOAPODS: 1.9.1

View File

@@ -1,10 +1,3 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
// !$*UTF8*$! // !$*UTF8*$!
{ {
archiveVersion = 1; archiveVersion = 1;
@@ -178,7 +171,6 @@
13687D401DF8748300E7C260 /* Frameworks */, 13687D401DF8748300E7C260 /* Frameworks */,
13687D411DF8748300E7C260 /* Resources */, 13687D411DF8748300E7C260 /* Resources */,
FA2FB9DD6471BDD3FBCE503B /* [CP] Embed Pods Frameworks */, FA2FB9DD6471BDD3FBCE503B /* [CP] Embed Pods Frameworks */,
6E01EB987F1564F3D71EBE5A /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -233,6 +225,7 @@
developmentRegion = English; developmentRegion = English;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
knownRegions = ( knownRegions = (
English,
en, en,
Base, Base,
); );
@@ -272,28 +265,16 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
); );
name = "[CP] Check Pods Manifest.lock"; name = "[CP] Check Pods Manifest.lock";
outputPaths = ( outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-YogaKitSample-checkManifestLockResult.txt",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
6E01EB987F1564F3D71EBE5A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample-resources.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
FA2FB9DD6471BDD3FBCE503B /* [CP] Embed Pods Frameworks */ = { FA2FB9DD6471BDD3FBCE503B /* [CP] Embed Pods Frameworks */ = {
@@ -302,13 +283,18 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/IGListDiffKit/IGListDiffKit.framework",
"${BUILT_PRODUCTS_DIR}/IGListKit/IGListKit.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IGListDiffKit.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/IGListKit.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-YogaKitSample/Pods-YogaKitSample-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@@ -446,7 +432,7 @@
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0; SWIFT_VERSION = 5.0;
}; };
name = Debug; name = Debug;
}; };
@@ -461,7 +447,7 @@
PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample; PRODUCT_BUNDLE_IDENTIFIER = com.facebook.YogaKitSample;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_INSTALL_OBJC_HEADER = NO;
SWIFT_VERSION = 3.0; SWIFT_VERSION = 5.0;
}; };
name = Release; name = Release;
}; };

View File

@@ -18,12 +18,12 @@ private final class ExampleModel {
} }
} }
extension ExampleModel: IGListDiffable { extension ExampleModel: ListDiffable {
fileprivate func diffIdentifier() -> NSObjectProtocol { fileprivate func diffIdentifier() -> NSObjectProtocol {
return title as NSString return title as NSString
} }
fileprivate func isEqual(toDiffableObject object: IGListDiffable?) -> Bool { fileprivate func isEqual(toDiffableObject object: ListDiffable?) -> Bool {
guard let otherObj = object as? ExampleModel else { return false } guard let otherObj = object as? ExampleModel else { return false }
return (title == otherObj.title) && return (title == otherObj.title) &&
@@ -31,11 +31,11 @@ extension ExampleModel: IGListDiffable {
} }
} }
final class ExamplesViewController: UIViewController, IGListAdapterDataSource, IGListSingleSectionControllerDelegate { final class ExamplesViewController: UIViewController, ListAdapterDataSource, ListSingleSectionControllerDelegate {
private lazy var adapter: IGListAdapter = { private lazy var adapter: ListAdapter = {
return IGListAdapter(updater: IGListAdapterUpdater(), viewController: self, workingRangeSize: 0) return ListAdapter(updater: ListAdapterUpdater(), viewController: self, workingRangeSize: 0)
}() }()
private let collectionView = IGListCollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) private let collectionView = ListCollectionView(frame: .zero)
// Update this to array to create more examples. // Update this to array to create more examples.
@@ -47,6 +47,7 @@ final class ExamplesViewController: UIViewController, IGListAdapterDataSource, I
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
title = "Examples" title = "Examples"
collectionView.backgroundColor = .clear
view.addSubview(collectionView) view.addSubview(collectionView)
adapter.collectionView = collectionView adapter.collectionView = collectionView
adapter.dataSource = self adapter.dataSource = self
@@ -59,16 +60,16 @@ final class ExamplesViewController: UIViewController, IGListAdapterDataSource, I
//MARK: IGListAdapterDataSource //MARK: IGListAdapterDataSource
func objects(for listAdapter: IGListAdapter) -> [IGListDiffable] { func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
return models as [IGListDiffable] return models as [ListDiffable]
} }
func listAdapter(_ listAdapter: IGListAdapter, sectionControllerFor object: Any) -> IGListSectionController { func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
let sizeBlock: IGListSingleSectionCellSizeBlock = { (model, context) in let sizeBlock: ListSingleSectionCellSizeBlock = { (model, context) in
return CGSize(width: (context?.containerSize.width)!, height: 75.0) return CGSize(width: (context?.containerSize.width)!, height: 75.0)
} }
let configureBlock: IGListSingleSectionCellConfigureBlock = { (model, cell) in let configureBlock: ListSingleSectionCellConfigureBlock = { (model, cell) in
guard let m = model as? ExampleModel, let c = cell as? SingleLabelCollectionCell else { guard let m = model as? ExampleModel, let c = cell as? SingleLabelCollectionCell else {
return return
} }
@@ -76,18 +77,18 @@ final class ExamplesViewController: UIViewController, IGListAdapterDataSource, I
c.label.text = m.title c.label.text = m.title
} }
let sectionController = IGListSingleSectionController(cellClass: SingleLabelCollectionCell.self, let sectionController = ListSingleSectionController(cellClass: SingleLabelCollectionCell.self,
configureBlock: configureBlock, configureBlock: configureBlock,
sizeBlock: sizeBlock) sizeBlock: sizeBlock)
sectionController.selectionDelegate = self sectionController.selectionDelegate = self
return sectionController return sectionController
} }
func emptyView(for listAdapter: IGListAdapter) -> UIView? { return nil } func emptyView(for listAdapter: ListAdapter) -> UIView? { return nil }
//MARK: IGListSingleSectionControllerDelegate //MARK: IGListSingleSectionControllerDelegate
func didSelect(_ sectionController: IGListSingleSectionController) { func didSelect(_ sectionController: ListSingleSectionController, with object: Any) {
let section = adapter.section(for: sectionController) let section = adapter.section(for: sectionController)
let model = models[section] let model = models[section]

View File

@@ -32,5 +32,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
</dict> </dict>
</plist> </plist>

View File

@@ -32,22 +32,24 @@ final class BasicViewController: UIViewController {
} }
root.addSubview(child1) root.addSubview(child1)
let child2 = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 200)) let child2 = UIView()
child2.backgroundColor = .green child2.backgroundColor = .green
child2.configureLayout { (layout) in child2.configureLayout { (layout) in
layout.isEnabled = true layout.isEnabled = true
layout.alignSelf = .flexEnd layout.alignSelf = .flexEnd
layout.width = 200
layout.height = 200
} }
root.addSubview(child2) root.addSubview(child2)
let child3 = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) let child3 = UIView()
child3.backgroundColor = .yellow child3.backgroundColor = .yellow
child3.configureLayout { (layout) in child3.configureLayout { (layout) in
layout.isEnabled = true layout.isEnabled = true
layout.alignSelf = .flexStart layout.alignSelf = .flexStart
layout.width = 100
layout.height = 100
} }
root.addSubview(child3) root.addSubview(child3)
root.yoga.applyLayout(preservingOrigin: true)
} }
} }

View File

@@ -51,9 +51,9 @@ final class LayoutInclusionViewController: UIViewController {
} }
contentView.addSubview(disappearingView) contentView.addSubview(disappearingView)
button.setTitle("Add Blue View", for: UIControlState.selected) button.setTitle("Add Blue View", for: .selected)
button.setTitle("Remove Blue View", for: UIControlState.normal) button.setTitle("Remove Blue View", for: .normal)
button.addTarget(self, action: #selector(buttonWasTapped), for: UIControlEvents.touchUpInside) button.addTarget(self, action: #selector(buttonWasTapped), for: UIControl.Event.touchUpInside)
button.configureLayout { (layout) in button.configureLayout { (layout) in
layout.isEnabled = true layout.isEnabled = true
layout.height = 300 layout.height = 300
@@ -61,12 +61,10 @@ final class LayoutInclusionViewController: UIViewController {
layout.alignSelf = .center layout.alignSelf = .center
} }
root.addSubview(button) root.addSubview(button)
root.yoga.applyLayout(preservingOrigin: false)
} }
// MARK - UIButton Action // MARK - UIButton Action
func buttonWasTapped() { @objc func buttonWasTapped() {
button.isSelected = !button.isSelected button.isSelected = !button.isSelected
button.isUserInteractionEnabled = false button.isUserInteractionEnabled = false

View File

@@ -42,7 +42,6 @@ final class SingleLabelCollectionCell: UICollectionViewCell {
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
contentView.yoga.applyLayout(preservingOrigin: false)
label.frame = contentView.bounds label.frame = contentView.bounds
} }
} }