From 9e3b4f8752afcd1810979cd627f6ae8aa8047b47 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Sat, 23 May 2020 23:23:30 -0400
Subject: [PATCH 01/23] Pod install
---
Example/PinLayoutSample.xcodeproj/project.pbxproj | 4 ----
.../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++
Podfile.lock | 4 ++--
3 files changed, 10 insertions(+), 6 deletions(-)
create mode 100644 Example/PinLayoutSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
diff --git a/Example/PinLayoutSample.xcodeproj/project.pbxproj b/Example/PinLayoutSample.xcodeproj/project.pbxproj
index b785bf1a..05eb9d88 100644
--- a/Example/PinLayoutSample.xcodeproj/project.pbxproj
+++ b/Example/PinLayoutSample.xcodeproj/project.pbxproj
@@ -41,7 +41,6 @@
24F246141FA8D57100B6332E /* UIImageView+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F246131FA8D57100B6332E /* UIImageView+Download.swift */; };
24F75B5B1EE5644E008DB567 /* IntroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F75B591EE5644E008DB567 /* IntroView.swift */; };
24F75B5C1EE5644E008DB567 /* IntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F75B5A1EE5644E008DB567 /* IntroViewController.swift */; };
- DE6C3D736B571B80E207DF6A /* Pods_PinLayoutSample.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AAD69688AA2A3F0994F3074E /* Pods_PinLayoutSample.framework */; };
DF390898211900320049FD56 /* AnimationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF390897211900320049FD56 /* AnimationsView.swift */; };
DF39089A211900480049FD56 /* AnimationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF390899211900480049FD56 /* AnimationsViewController.swift */; };
DF4C1AA4205AEDFC00DED50B /* SafeAreaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF4C1AA0205AEDFC00DED50B /* SafeAreaView.swift */; };
@@ -148,7 +147,6 @@
24F75B591EE5644E008DB567 /* IntroView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroView.swift; sourceTree = ""; };
24F75B5A1EE5644E008DB567 /* IntroViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroViewController.swift; sourceTree = ""; };
A35A00E6536E49A548E763E6 /* Pods-PinLayoutSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutSample.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-PinLayoutSample/Pods-PinLayoutSample.debug.xcconfig"; sourceTree = ""; };
- AAD69688AA2A3F0994F3074E /* Pods_PinLayoutSample.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_PinLayoutSample.framework; sourceTree = BUILT_PRODUCTS_DIR; };
C589624E868FCB20F7C10918 /* Pods-PinLayoutSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutSample.release.xcconfig"; path = "../Pods/Target Support Files/Pods-PinLayoutSample/Pods-PinLayoutSample.release.xcconfig"; sourceTree = ""; };
DF390897211900320049FD56 /* AnimationsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimationsView.swift; path = PinLayoutSample/UI/Examples/Animations/AnimationsView.swift; sourceTree = SOURCE_ROOT; };
DF390899211900480049FD56 /* AnimationsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationsViewController.swift; sourceTree = ""; };
@@ -173,7 +171,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- DE6C3D736B571B80E207DF6A /* Pods_PinLayoutSample.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -183,7 +180,6 @@
160FB83905049FCEDD18DC8A /* Frameworks */ = {
isa = PBXGroup;
children = (
- AAD69688AA2A3F0994F3074E /* Pods_PinLayoutSample.framework */,
246812FC1F8D013500462E53 /* NotificationCenter.framework */,
);
name = Frameworks;
diff --git a/Example/PinLayoutSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Example/PinLayoutSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/Example/PinLayoutSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/Podfile.lock b/Podfile.lock
index dcdba953..32a1f5c6 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -1,6 +1,6 @@
PODS:
- Nimble (8.0.2)
- - PinLayout (1.8.10)
+ - PinLayout (1.8.13)
- Quick (2.1.0)
- SwiftLint (0.35.0)
@@ -22,7 +22,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
Nimble: 622629381bda1dd5678162f21f1368cec7cbba60
- PinLayout: 641bc9679f73d3da35e04bb5180547cf55fd92d7
+ PinLayout: e41a50260a76508b7a7fcee8955c76639adc69bc
Quick: 4be43f6634acfa727dd106bdf3929ce125ffa79d
SwiftLint: 5553187048b900c91aa03552807681bb6b027846
From 089ebe9eb2d655851eda2031a51965ce9054a472 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Sun, 24 May 2020 00:00:42 -0400
Subject: [PATCH 02/23] Working prototype
---
.../Subviews/ChoiceSelectorView.swift | 18 +++-----
PinLayout.xcodeproj/project.pbxproj | 9 +++-
Sources/AutoSizeCalculable.swift | 12 +++++
Sources/Extensions/UIView+PinLayout.swift | 45 +++++++++++++++++++
Sources/Impl/PinLayout+Layouting.swift | 8 +++-
Sources/Pin.swift | 2 +
6 files changed, 80 insertions(+), 14 deletions(-)
create mode 100644 Sources/AutoSizeCalculable.swift
diff --git a/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift b/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift
index fc030c39..f0b682da 100644
--- a/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift
+++ b/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift
@@ -46,21 +46,13 @@ class ChoiceSelectorView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
- _ = layout()
+ layout()
}
- override func sizeThatFits(_ size: CGSize) -> CGSize {
- // 1) Set the width to the specified width
- self.pin.width(size.width)
-
- // 2) Layout the contentView's controls
- return layout()
- }
-
- private func layout() -> CGSize {
+ private func layout() {
let margin: CGFloat = 12
- if frame.width > 500 {
+ if bounds.width > 500 {
// The UISegmentedControl is at the top-right corner and the label takes the remaining horizontal space.
segmentedControl.pin.top().right().margin(margin)
textLabel.pin.top().left().before(of: segmentedControl).margin(margin).sizeToFit(.width)
@@ -69,7 +61,9 @@ class ChoiceSelectorView: UIView {
textLabel.pin.top().horizontally().margin(margin).sizeToFit(.width)
segmentedControl.pin.below(of: textLabel).right().margin(margin)
}
+ }
- return CGSize(width: frame.width, height: max(textLabel.frame.maxY, segmentedControl.frame.maxY) + margin)
+ override func sizeThatFits(_ size: CGSize) -> CGSize {
+ return autoSizeThatFits(size) { layout() }
}
}
diff --git a/PinLayout.xcodeproj/project.pbxproj b/PinLayout.xcodeproj/project.pbxproj
index e5175b65..701e8fff 100644
--- a/PinLayout.xcodeproj/project.pbxproj
+++ b/PinLayout.xcodeproj/project.pbxproj
@@ -44,6 +44,9 @@
C80435D720D08A2C00EB1BD7 /* SizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */; };
C80435D820D08B7300EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; };
C80435D920D08B7400EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; };
+ C8291E41247A242600E95886 /* AutoSizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8291E40247A242600E95886 /* AutoSizeCalculable.swift */; };
+ C8291E42247A243900E95886 /* AutoSizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8291E40247A242600E95886 /* AutoSizeCalculable.swift */; };
+ C8291E43247A243900E95886 /* AutoSizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8291E40247A242600E95886 /* AutoSizeCalculable.swift */; };
C82DC20C20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; };
C82DC20D20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; };
C82DC20E20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; };
@@ -230,6 +233,7 @@
A55FA6F0D7AFC9918887FBF2 /* Pods-PinLayoutTests-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutTests-iOS.release.xcconfig"; path = "Target Support Files/Pods-PinLayoutTests-iOS/Pods-PinLayoutTests-iOS.release.xcconfig"; sourceTree = ""; };
C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeCalculable.swift; sourceTree = ""; };
C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Layoutable+PinLayout.swift"; sourceTree = ""; };
+ C8291E40247A242600E95886 /* AutoSizeCalculable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoSizeCalculable.swift; sourceTree = ""; };
C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layoutable.swift; sourceTree = ""; };
C83588BF20DBC5E600D6E8F9 /* CALayerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CALayerSpec.swift; sourceTree = ""; };
C83600A520E2949200A3D891 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; usesTabs = 1; };
@@ -375,6 +379,7 @@
DF702D8C20D33BA90062045C /* PinLayout+Size.swift */,
DF702D8B20D33BA90062045C /* PinLayout+WrapContent.swift */,
C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */,
+ C8291E40247A242600E95886 /* AutoSizeCalculable.swift */,
DFF222CC20B999BD00AC2A84 /* Types.swift */,
DF702DA720D33D2A0062045C /* Extensions */,
DFA06B031E8B38B300B6D5E7 /* Impl */,
@@ -418,7 +423,6 @@
DE878C8BA276883C90524382 /* Pods-PinLayoutTests-tvOS.debug.xcconfig */,
89672C5CCF1F123104855629 /* Pods-PinLayoutTests-tvOS.release.xcconfig */,
);
- name = Pods;
path = Pods;
sourceTree = "";
};
@@ -895,6 +899,7 @@
DF46F686212442EF0055B081 /* PEdgeInsets+Operators.swift in Sources */,
DF702DA520D33CFA0062045C /* PinLayout+Layouting.swift in Sources */,
DF702DA620D33CFA0062045C /* PinLayout+Warning.swift in Sources */,
+ C8291E43247A243900E95886 /* AutoSizeCalculable.swift in Sources */,
DF702DAF20D33D6A0062045C /* UIView+PinLayout.swift in Sources */,
DF702D9D20D33CF20062045C /* PinLayout.swift in Sources */,
);
@@ -927,6 +932,7 @@
DF46F684212442EE0055B081 /* PEdgeInsets+Operators.swift in Sources */,
24949A2E1EF69474003643D3 /* Filters.swift in Sources */,
DFB3ECB12061602F005F226B /* PinSafeArea.swift in Sources */,
+ C8291E41247A242600E95886 /* AutoSizeCalculable.swift in Sources */,
DF702DAB20D33D660062045C /* UIView+PinLayout.swift in Sources */,
C80435D520D0898000EB1BD7 /* Layoutable+PinLayout.swift in Sources */,
);
@@ -1018,6 +1024,7 @@
DF46F685212442EE0055B081 /* PEdgeInsets+Operators.swift in Sources */,
DF702DA220D33CF90062045C /* PinLayout+Layouting.swift in Sources */,
DF702DA320D33CF90062045C /* PinLayout+Warning.swift in Sources */,
+ C8291E42247A243900E95886 /* AutoSizeCalculable.swift in Sources */,
DF702DAD20D33D6A0062045C /* UIView+PinLayout.swift in Sources */,
DF702D9920D33CF10062045C /* PinLayout.swift in Sources */,
);
diff --git a/Sources/AutoSizeCalculable.swift b/Sources/AutoSizeCalculable.swift
new file mode 100644
index 00000000..78d14070
--- /dev/null
+++ b/Sources/AutoSizeCalculable.swift
@@ -0,0 +1,12 @@
+#if os(iOS) || os(tvOS)
+import UIKit
+#else
+import AppKit
+#endif
+
+public protocol AutoSizeCalculable {
+ var autoSizingRect: CGRect? { get set }
+ var autoSizingRectWithMargins: CGRect? { get set }
+
+ func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize
+}
diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift
index fb0a870d..6bd7030a 100644
--- a/Sources/Extensions/UIView+PinLayout.swift
+++ b/Sources/Extensions/UIView+PinLayout.swift
@@ -38,6 +38,8 @@ extension UIView: Layoutable, SizeCalculable {
}
public func getRect(keepTransform: Bool) -> CGRect {
+ guard !Pin.autoSizingInProgress || autoSizingRect == nil else { return autoSizingRect ?? CGRect.zero }
+
if keepTransform {
/*
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
@@ -59,6 +61,11 @@ extension UIView: Layoutable, SizeCalculable {
public func setRect(_ rect: CGRect, keepTransform: Bool) {
let adjustedRect = Coordinates.adjustRectToDisplayScale(rect)
+ guard !Pin.autoSizingInProgress else {
+ autoSizingRect = adjustedRect
+ return
+ }
+
if keepTransform {
/*
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
@@ -95,4 +102,42 @@ extension UIView: Layoutable, SizeCalculable {
}
}
+extension UIView: AutoSizeCalculable {
+ private struct pinlayoutAssociatedKeys {
+ static var pinlayoutAutoSizingRect = UnsafeMutablePointer.allocate(capacity: 1)
+ static var pinlayoutAutoSizingRectWithMargins = UnsafeMutablePointer.allocate(capacity: 1)
+ }
+
+ public var autoSizingRect: CGRect? {
+ get {
+ return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRect) as? CGRect
+ }
+ set {
+ objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRect, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ }
+ }
+
+ public var autoSizingRectWithMargins: CGRect? {
+ get {
+ return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRectWithMargins) as? CGRect
+ }
+ set {
+ objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRectWithMargins, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
+ }
+ }
+
+ public func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize {
+ Pin.autoSizingInProgress = true
+ autoSizingRect = CGRect(origin: CGPoint.zero, size: size)
+ layoutClosure()
+
+ let boundingRect = subviews.compactMap({ $0.autoSizingRectWithMargins }).reduce(CGRect.zero) { (result: CGRect, autoSizingRect: CGRect) -> CGRect in
+ return result.union(autoSizingRect)
+ }
+
+ Pin.autoSizingInProgress = false
+ return boundingRect.size
+ }
+}
+
#endif
diff --git a/Sources/Impl/PinLayout+Layouting.swift b/Sources/Impl/PinLayout+Layouting.swift
index efc69e90..50259449 100644
--- a/Sources/Impl/PinLayout+Layouting.swift
+++ b/Sources/Impl/PinLayout+Layouting.swift
@@ -133,7 +133,13 @@ extension PinLayout {
if !validateComputedHeight(newRect.size.height) {
newRect.size.height = view.getRect(keepTransform: keepTransform).height
}
-
+
+ if Pin.autoSizingInProgress, var autoSizeCalculable = view as? AutoSizeCalculable {
+ let marginInsets = UIEdgeInsets(top: -_marginTop, left: -_marginLeft, bottom: -_marginBottom, right: -_marginRight)
+ let rectWithMargins = newRect.inset(by: marginInsets)
+ autoSizeCalculable.autoSizingRectWithMargins = rectWithMargins
+ }
+
/*
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
view's transform (UIView.transform).
diff --git a/Sources/Pin.swift b/Sources/Pin.swift
index 9c023b58..08842a02 100644
--- a/Sources/Pin.swift
+++ b/Sources/Pin.swift
@@ -45,6 +45,8 @@ import Foundation
self.layoutDirection = direction
}
+ internal static var autoSizingInProgress: Bool = false
+
//
// Warnings
//
From faeb5988ee5d32cc6e1338b7f4402e599b313a6c Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Sat, 13 Jun 2020 15:39:02 -0400
Subject: [PATCH 03/23] Code review modifications
---
Sources/AutoSizeCalculable.swift | 4 +---
Sources/Extensions/UIView+PinLayout.swift | 14 +++++++-------
Sources/Impl/PinLayout+Layouting.swift | 5 ++---
3 files changed, 10 insertions(+), 13 deletions(-)
diff --git a/Sources/AutoSizeCalculable.swift b/Sources/AutoSizeCalculable.swift
index 78d14070..69782ff0 100644
--- a/Sources/AutoSizeCalculable.swift
+++ b/Sources/AutoSizeCalculable.swift
@@ -5,8 +5,6 @@ import AppKit
#endif
public protocol AutoSizeCalculable {
- var autoSizingRect: CGRect? { get set }
- var autoSizingRectWithMargins: CGRect? { get set }
-
+ func setAutoSizingRect(_ rect: CGRect, margins: PEdgeInsets)
func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize
}
diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift
index 6bd7030a..b89e1588 100644
--- a/Sources/Extensions/UIView+PinLayout.swift
+++ b/Sources/Extensions/UIView+PinLayout.swift
@@ -61,11 +61,6 @@ extension UIView: Layoutable, SizeCalculable {
public func setRect(_ rect: CGRect, keepTransform: Bool) {
let adjustedRect = Coordinates.adjustRectToDisplayScale(rect)
- guard !Pin.autoSizingInProgress else {
- autoSizingRect = adjustedRect
- return
- }
-
if keepTransform {
/*
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
@@ -108,7 +103,7 @@ extension UIView: AutoSizeCalculable {
static var pinlayoutAutoSizingRectWithMargins = UnsafeMutablePointer.allocate(capacity: 1)
}
- public var autoSizingRect: CGRect? {
+ private var autoSizingRect: CGRect? {
get {
return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRect) as? CGRect
}
@@ -117,7 +112,7 @@ extension UIView: AutoSizeCalculable {
}
}
- public var autoSizingRectWithMargins: CGRect? {
+ private var autoSizingRectWithMargins: CGRect? {
get {
return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRectWithMargins) as? CGRect
}
@@ -126,6 +121,11 @@ extension UIView: AutoSizeCalculable {
}
}
+ public func setAutoSizingRect(_ rect: CGRect, margins: PEdgeInsets) {
+ self.autoSizingRect = Coordinates.adjustRectToDisplayScale(rect)
+ self.autoSizingRectWithMargins = Coordinates.adjustRectToDisplayScale(rect.inset(by: margins))
+ }
+
public func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize {
Pin.autoSizingInProgress = true
autoSizingRect = CGRect(origin: CGPoint.zero, size: size)
diff --git a/Sources/Impl/PinLayout+Layouting.swift b/Sources/Impl/PinLayout+Layouting.swift
index 50259449..1ce78596 100644
--- a/Sources/Impl/PinLayout+Layouting.swift
+++ b/Sources/Impl/PinLayout+Layouting.swift
@@ -134,10 +134,9 @@ extension PinLayout {
newRect.size.height = view.getRect(keepTransform: keepTransform).height
}
- if Pin.autoSizingInProgress, var autoSizeCalculable = view as? AutoSizeCalculable {
+ if Pin.autoSizingInProgress, let autoSizeCalculable = view as? AutoSizeCalculable {
let marginInsets = UIEdgeInsets(top: -_marginTop, left: -_marginLeft, bottom: -_marginBottom, right: -_marginRight)
- let rectWithMargins = newRect.inset(by: marginInsets)
- autoSizeCalculable.autoSizingRectWithMargins = rectWithMargins
+ autoSizeCalculable.setAutoSizingRect(newRect, margins: marginInsets)
}
/*
From 3437838c8b4bf52a101f109723d0ff7d0fbdfdbc Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Sat, 13 Jun 2020 15:41:33 -0400
Subject: [PATCH 04/23] Revert "Adjust to Container Size" sample code
---
.../Subviews/ChoiceSelectorView.swift | 18 ++++++++++++------
1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift b/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift
index f0b682da..fc030c39 100644
--- a/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift
+++ b/Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift
@@ -46,13 +46,21 @@ class ChoiceSelectorView: UIView {
override func layoutSubviews() {
super.layoutSubviews()
- layout()
+ _ = layout()
}
- private func layout() {
+ override func sizeThatFits(_ size: CGSize) -> CGSize {
+ // 1) Set the width to the specified width
+ self.pin.width(size.width)
+
+ // 2) Layout the contentView's controls
+ return layout()
+ }
+
+ private func layout() -> CGSize {
let margin: CGFloat = 12
- if bounds.width > 500 {
+ if frame.width > 500 {
// The UISegmentedControl is at the top-right corner and the label takes the remaining horizontal space.
segmentedControl.pin.top().right().margin(margin)
textLabel.pin.top().left().before(of: segmentedControl).margin(margin).sizeToFit(.width)
@@ -61,9 +69,7 @@ class ChoiceSelectorView: UIView {
textLabel.pin.top().horizontally().margin(margin).sizeToFit(.width)
segmentedControl.pin.below(of: textLabel).right().margin(margin)
}
- }
- override func sizeThatFits(_ size: CGSize) -> CGSize {
- return autoSizeThatFits(size) { layout() }
+ return CGSize(width: frame.width, height: max(textLabel.frame.maxY, segmentedControl.frame.maxY) + margin)
}
}
From 97aba2e82a0719490eafc6c919c45347ccdc0d20 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 07:53:36 -0400
Subject: [PATCH 05/23] Change Travis target OS from 13.2 to 13.2.2
---
build-ci.sh | 28 ++++++++++++++--------------
1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/build-ci.sh b/build-ci.sh
index 4c395e57..8d13ef31 100755
--- a/build-ci.sh
+++ b/build-ci.sh
@@ -8,16 +8,16 @@ echo "===============================" &&
echo "PinLayout-iOS" &&
echo "===============================" &&
time xcodebuild build -project PinLayout.xcodeproj -scheme PinLayout-iOS \
- -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2' \
+ -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2.2 \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
| xcpretty &&
echo "===============================" &&
echo "PinLayout-tvOS" &&
echo "===============================" &&
time xcodebuild build -project PinLayout.xcodeproj -scheme PinLayout-tvOS \
- -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.2 \
- -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.2' \
+ -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.2.2 \
+ -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.2.2' \
| xcpretty &&
echo "===============================" &&
@@ -50,7 +50,7 @@ time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-i
time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS \
-derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2' \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
| xcpretty &&
# echo "==============================="
@@ -80,8 +80,8 @@ cd TestProjects/cocoapods/ios &&
rm -rf $DERIVED_DATA &&
pod install &&
time xcodebuild clean build -workspace PinLayout-iOS.xcworkspace -scheme PinLayout-iOS \
- -sdk iphonesimulator13.2 -derivedDataPath $DERIVED_DATA \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2' \
+ -sdk iphonesimulator13.2.2 -derivedDataPath $DERIVED_DATA \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
| xcpretty &&
cd ../../.. &&
@@ -105,8 +105,8 @@ cd TestProjects/cocoapods/tvos &&
rm -rf $DERIVED_DATA &&
pod install &&
time xcodebuild clean build -workspace PinLayout-tvOS.xcworkspace -scheme PinLayout-tvOS \
- -sdk appletvsimulator13.2 -derivedDataPath $DERIVED_DATA \
- -destination 'platform=tvOS Simulator,name=Apple TV,OS=13.2' \
+ -sdk appletvsimulator13.2.2 -derivedDataPath $DERIVED_DATA \
+ -destination 'platform=tvOS Simulator,name=Apple TV,OS=13.2.2' \
| xcpretty &&
cd ../../.. &&
@@ -120,9 +120,9 @@ rm Cartfile &&
echo "git \"$TRAVIS_BUILD_DIR\" \"$TRAVIS_BRANCH\"" > Cartfile &&
carthage update --use-ssh --platform iOS &&
time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj \
- -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.2 \
+ -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.2.2 \
-derivedDataPath $DERIVED_DATA \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2' \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
| xcpretty &&
cd ../../.. &&
@@ -139,10 +139,10 @@ time bundle exec pod lib lint --allow-warnings
# rm -rf .build
# rm Package.pins
# swift package show-dependencies --format json
-# time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.2 -derivedDataPath $DERIVED_DATA \
-# -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2' \
+# time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.2.2 -derivedDataPath $DERIVED_DATA \
+# -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
# | xcpretty
# cd ../../..
#
# #OTHER_SWIFT_FLAGS='-Xfrontend -debug-time-function-bodies'
-# xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS -derivedDataPath $DERIVED_DATA -sdk macosx10.15
\ No newline at end of file
+# xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS -derivedDataPath $DERIVED_DATA -sdk macosx10.15
From 511be9e56123cb7fee01826a5a7995454da7d933 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 08:57:55 -0400
Subject: [PATCH 06/23] Update test platform to xcode 11.5 iOS 13.5
---
.travis.yml | 2 +-
build-ci.sh | 26 +++++++++++++-------------
2 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 7a58334e..3b54ea89 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,5 @@
language: objective-c
-osx_image: xcode11.2
+osx_image: xcode11.5
cache:
- bundler
diff --git a/build-ci.sh b/build-ci.sh
index 8d13ef31..b472cd12 100755
--- a/build-ci.sh
+++ b/build-ci.sh
@@ -8,16 +8,16 @@ echo "===============================" &&
echo "PinLayout-iOS" &&
echo "===============================" &&
time xcodebuild build -project PinLayout.xcodeproj -scheme PinLayout-iOS \
- -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2.2 \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
+ -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.5 \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
| xcpretty &&
echo "===============================" &&
echo "PinLayout-tvOS" &&
echo "===============================" &&
time xcodebuild build -project PinLayout.xcodeproj -scheme PinLayout-tvOS \
- -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.2.2 \
- -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.2.2' \
+ -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.5 \
+ -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.5' \
| xcpretty &&
echo "===============================" &&
@@ -50,7 +50,7 @@ time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-i
time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS \
-derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
| xcpretty &&
# echo "==============================="
@@ -80,8 +80,8 @@ cd TestProjects/cocoapods/ios &&
rm -rf $DERIVED_DATA &&
pod install &&
time xcodebuild clean build -workspace PinLayout-iOS.xcworkspace -scheme PinLayout-iOS \
- -sdk iphonesimulator13.2.2 -derivedDataPath $DERIVED_DATA \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
+ -sdk iphonesimulator13.5 -derivedDataPath $DERIVED_DATA \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
| xcpretty &&
cd ../../.. &&
@@ -105,8 +105,8 @@ cd TestProjects/cocoapods/tvos &&
rm -rf $DERIVED_DATA &&
pod install &&
time xcodebuild clean build -workspace PinLayout-tvOS.xcworkspace -scheme PinLayout-tvOS \
- -sdk appletvsimulator13.2.2 -derivedDataPath $DERIVED_DATA \
- -destination 'platform=tvOS Simulator,name=Apple TV,OS=13.2.2' \
+ -sdk appletvsimulator13.5 -derivedDataPath $DERIVED_DATA \
+ -destination 'platform=tvOS Simulator,name=Apple TV,OS=13.5' \
| xcpretty &&
cd ../../.. &&
@@ -120,9 +120,9 @@ rm Cartfile &&
echo "git \"$TRAVIS_BUILD_DIR\" \"$TRAVIS_BRANCH\"" > Cartfile &&
carthage update --use-ssh --platform iOS &&
time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj \
- -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.2.2 \
+ -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.5 \
-derivedDataPath $DERIVED_DATA \
- -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
+ -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
| xcpretty &&
cd ../../.. &&
@@ -139,8 +139,8 @@ time bundle exec pod lib lint --allow-warnings
# rm -rf .build
# rm Package.pins
# swift package show-dependencies --format json
-# time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.2.2 -derivedDataPath $DERIVED_DATA \
-# -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.2.2' \
+# time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.5 -derivedDataPath $DERIVED_DATA \
+# -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
# | xcpretty
# cd ../../..
#
From 90508999d431fd88238b06a88e19f2a07af60dd6 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 14:35:26 -0400
Subject: [PATCH 07/23] Use tvOS 13.4
---
build-ci.sh | 50 +++++++++++++++++++++++++-------------------------
1 file changed, 25 insertions(+), 25 deletions(-)
diff --git a/build-ci.sh b/build-ci.sh
index b472cd12..5f10a3ff 100755
--- a/build-ci.sh
+++ b/build-ci.sh
@@ -16,7 +16,7 @@ echo "===============================" &&
echo "PinLayout-tvOS" &&
echo "===============================" &&
time xcodebuild build -project PinLayout.xcodeproj -scheme PinLayout-tvOS \
- -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.5 \
+ -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.4 \
-destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.5' \
| xcpretty &&
@@ -42,7 +42,7 @@ time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-i
-derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
-destination 'platform=iOS Simulator,name=iPhone 7,OS=11.4' \
| xcpretty &&
-
+
time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS \
-derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
-destination 'platform=iOS Simulator,name=iPhone 8,OS=12.2' \
@@ -53,25 +53,25 @@ time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-i
-destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
| xcpretty &&
-# echo "==============================="
-# echo "tvOS unit test"
-# echo "==============================="
+# echo "==============================="
+# echo "tvOS unit test"
+# echo "==============================="
# time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-tvOS \
-# -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.2 \
+# -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.4 \
# -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=12.2' \
-# | xcpretty
+# | xcpretty
# time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-tvOS \
-# -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.2 \
+# -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.4 \
# -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.2' \
-# | xcpretty
+# | xcpretty
-# echo "==============================="
-# echo "macOS unit test"
-# echo "==============================="
+# echo "==============================="
+# echo "macOS unit test"
+# echo "==============================="
# time xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS \
# -derivedDataPath $DERIVED_DATA -sdk macosx10.15 \
-# | xcpretty
+# | xcpretty
echo "===============================" &&
echo " Cocoapods: iOS Empty project" &&
@@ -105,7 +105,7 @@ cd TestProjects/cocoapods/tvos &&
rm -rf $DERIVED_DATA &&
pod install &&
time xcodebuild clean build -workspace PinLayout-tvOS.xcworkspace -scheme PinLayout-tvOS \
- -sdk appletvsimulator13.5 -derivedDataPath $DERIVED_DATA \
+ -sdk appletvsimulator13.4 -derivedDataPath $DERIVED_DATA \
-destination 'platform=tvOS Simulator,name=Apple TV,OS=13.5' \
| xcpretty &&
cd ../../.. &&
@@ -131,18 +131,18 @@ echo " Pod lib lint" &&
echo "===============================" &&
time bundle exec pod lib lint --allow-warnings
-# echo "=========================================="
-# echo " Swift Package Manager: iOS Empty project "
-# echo "=========================================="
-# cd TestProjects/swift-package-manager/ios
-# rm -rf $DERIVED_DATA
-# rm -rf .build
+# echo "=========================================="
+# echo " Swift Package Manager: iOS Empty project "
+# echo "=========================================="
+# cd TestProjects/swift-package-manager/ios
+# rm -rf $DERIVED_DATA
+# rm -rf .build
# rm Package.pins
-# swift package show-dependencies --format json
+# swift package show-dependencies --format json
# time xcodebuild clean build -project PinLayout-Carthage-iOS.xcodeproj -scheme PinLayout-Carthage-iOS -sdk iphonesimulator13.5 -derivedDataPath $DERIVED_DATA \
# -destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
-# | xcpretty
-# cd ../../..
-#
+# | xcpretty
+# cd ../../..
+#
# #OTHER_SWIFT_FLAGS='-Xfrontend -debug-time-function-bodies'
-# xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS -derivedDataPath $DERIVED_DATA -sdk macosx10.15
+# xcodebuild clean test -workspace PinLayout.xcworkspace -scheme PinLayout-macOS -derivedDataPath $DERIVED_DATA -sdk macosx10.15
From 833a710ad9b944fc8ae774ae4f8cd487e95a3044 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 15:24:49 -0400
Subject: [PATCH 08/23] tvOS 13.4 (some refs remaining)
---
build-ci.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build-ci.sh b/build-ci.sh
index 5f10a3ff..e2cbb443 100755
--- a/build-ci.sh
+++ b/build-ci.sh
@@ -17,7 +17,7 @@ echo "PinLayout-tvOS" &&
echo "===============================" &&
time xcodebuild build -project PinLayout.xcodeproj -scheme PinLayout-tvOS \
-derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.4 \
- -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.5' \
+ -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.4' \
| xcpretty &&
echo "===============================" &&
@@ -63,7 +63,7 @@ time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-i
# time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-tvOS \
# -derivedDataPath $DERIVED_DATA -sdk appletvsimulator13.4 \
-# -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.2' \
+# -destination 'platform=tvOS Simulator,name=Apple TV 4K,OS=13.4' \
# | xcpretty
# echo "==============================="
From ff9caff54739879798e2820b555240d205123e5d Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 15:36:20 -0400
Subject: [PATCH 09/23] Again...
---
build-ci.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/build-ci.sh b/build-ci.sh
index e2cbb443..60248a46 100755
--- a/build-ci.sh
+++ b/build-ci.sh
@@ -106,7 +106,7 @@ rm -rf $DERIVED_DATA &&
pod install &&
time xcodebuild clean build -workspace PinLayout-tvOS.xcworkspace -scheme PinLayout-tvOS \
-sdk appletvsimulator13.4 -derivedDataPath $DERIVED_DATA \
- -destination 'platform=tvOS Simulator,name=Apple TV,OS=13.5' \
+ -destination 'platform=tvOS Simulator,name=Apple TV,OS=13.4' \
| xcpretty &&
cd ../../.. &&
From c55f4f60d452215fada076f3bfa993db8ff296a0 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 15:36:43 -0400
Subject: [PATCH 10/23] Fix recursive usage of auto sizing
---
Sources/Extensions/UIView+PinLayout.swift | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift
index b89e1588..2f551234 100644
--- a/Sources/Extensions/UIView+PinLayout.swift
+++ b/Sources/Extensions/UIView+PinLayout.swift
@@ -127,15 +127,23 @@ extension UIView: AutoSizeCalculable {
}
public func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize {
- Pin.autoSizingInProgress = true
- autoSizingRect = CGRect(origin: CGPoint.zero, size: size)
+ let isAlreadyAutoSizing = Pin.autoSizingInProgress
+
+ if (!isAlreadyAutoSizing) {
+ Pin.autoSizingInProgress = true
+ autoSizingRect = CGRect(origin: CGPoint.zero, size: size)
+ }
+
layoutClosure()
let boundingRect = subviews.compactMap({ $0.autoSizingRectWithMargins }).reduce(CGRect.zero) { (result: CGRect, autoSizingRect: CGRect) -> CGRect in
return result.union(autoSizingRect)
}
- Pin.autoSizingInProgress = false
+ if !isAlreadyAutoSizing {
+ Pin.autoSizingInProgress = false
+ }
+
return boundingRect.size
}
}
From e959028c6a56be22eaaa34996b2b5509c863a05b Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Tue, 16 Jun 2020 16:44:07 -0400
Subject: [PATCH 11/23] Fix rectWithMargins calculation on tvOS
---
Sources/Extensions/UIView+PinLayout.swift | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift
index 2f551234..831f9601 100644
--- a/Sources/Extensions/UIView+PinLayout.swift
+++ b/Sources/Extensions/UIView+PinLayout.swift
@@ -122,8 +122,14 @@ extension UIView: AutoSizeCalculable {
}
public func setAutoSizingRect(_ rect: CGRect, margins: PEdgeInsets) {
+ #if os(tvOS)
+ let rectWithMargins = UIEdgeInsetsInsetRect(rect, margins)
+ #else
+ let rectWithMargins = rect.inset(by: margins)
+ #endif
+
self.autoSizingRect = Coordinates.adjustRectToDisplayScale(rect)
- self.autoSizingRectWithMargins = Coordinates.adjustRectToDisplayScale(rect.inset(by: margins))
+ self.autoSizingRectWithMargins = Coordinates.adjustRectToDisplayScale(rectWithMargins)
}
public func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize {
From 57e25ec29c5bae30b568ae2bb0b2ad12d00ed975 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Wed, 17 Jun 2020 09:09:43 -0400
Subject: [PATCH 12/23] Use PEdgeInsets instead of UIEdgeInsets
---
Sources/Impl/PinLayout+Layouting.swift | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Sources/Impl/PinLayout+Layouting.swift b/Sources/Impl/PinLayout+Layouting.swift
index 1ce78596..36f078b8 100644
--- a/Sources/Impl/PinLayout+Layouting.swift
+++ b/Sources/Impl/PinLayout+Layouting.swift
@@ -135,7 +135,7 @@ extension PinLayout {
}
if Pin.autoSizingInProgress, let autoSizeCalculable = view as? AutoSizeCalculable {
- let marginInsets = UIEdgeInsets(top: -_marginTop, left: -_marginLeft, bottom: -_marginBottom, right: -_marginRight)
+ let marginInsets = PEdgeInsets(top: -_marginTop, left: -_marginLeft, bottom: -_marginBottom, right: -_marginRight)
autoSizeCalculable.setAutoSizingRect(newRect, margins: marginInsets)
}
From 0544e17c6ffddc5550f35613a8d0290e69d370d8 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Wed, 17 Jun 2020 09:31:02 -0400
Subject: [PATCH 13/23] Fix simulator versions
---
build-ci.sh | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/build-ci.sh b/build-ci.sh
index 60248a46..8756e671 100755
--- a/build-ci.sh
+++ b/build-ci.sh
@@ -31,7 +31,7 @@ echo "===============================" &&
echo "PinLayoutSample" &&
echo "===============================" &&
time xcodebuild build -workspace PinLayout.xcworkspace -scheme PinLayoutSample \
- -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
+ -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.5 \
-destination 'platform=iOS Simulator,name=iPhone 7,OS=11.4' \
| xcpretty &&
@@ -39,17 +39,17 @@ echo "===============================" &&
echo "iOS unit test" &&
echo "===============================" &&
time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS \
- -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
+ -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.5 \
-destination 'platform=iOS Simulator,name=iPhone 7,OS=11.4' \
| xcpretty &&
time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS \
- -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
+ -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.5 \
-destination 'platform=iOS Simulator,name=iPhone 8,OS=12.2' \
| xcpretty &&
time xcodebuild build test -workspace PinLayout.xcworkspace -scheme PinLayout-iOS \
- -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.2 \
+ -derivedDataPath $DERIVED_DATA -sdk iphonesimulator13.5 \
-destination 'platform=iOS Simulator,name=iPhone 8,OS=13.5' \
| xcpretty &&
From df408dca71fd2d231f8530971be3bc77a9ae51c8 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Wed, 17 Jun 2020 10:43:09 -0400
Subject: [PATCH 14/23] Use consistent version of Swift across project
---
PinLayout.xcodeproj/project.pbxproj | 16 ++--------------
Sources/Extensions/UIView+PinLayout.swift | 8 +-------
2 files changed, 3 insertions(+), 21 deletions(-)
diff --git a/PinLayout.xcodeproj/project.pbxproj b/PinLayout.xcodeproj/project.pbxproj
index 701e8fff..c7d00bcc 100644
--- a/PinLayout.xcodeproj/project.pbxproj
+++ b/PinLayout.xcodeproj/project.pbxproj
@@ -1095,7 +1095,6 @@
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
- SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
@@ -1119,7 +1118,6 @@
SDKROOT = appletvos;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
- SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 9.0;
};
@@ -1183,7 +1181,7 @@
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 9.0;
VERSIONING_SYSTEM = "apple-generic";
@@ -1241,7 +1239,7 @@
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphonesimulator iphoneos";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
- SWIFT_VERSION = 4.0;
+ SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
TVOS_DEPLOYMENT_TARGET = 9.0;
VALIDATE_PRODUCT = YES;
@@ -1267,7 +1265,6 @@
PRODUCT_NAME = PinLayout;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
- SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -1287,7 +1284,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "com.mirego.PinLayout-iOS";
PRODUCT_NAME = PinLayout;
SKIP_INSTALL = YES;
- SWIFT_VERSION = 5.0;
};
name = Release;
};
@@ -1302,7 +1298,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mirego.PinLayoutTests;
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_VERSION = 5.0;
};
name = Debug;
};
@@ -1317,7 +1312,6 @@
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mirego.PinLayoutTests;
PRODUCT_NAME = "$(TARGET_NAME)";
- SWIFT_VERSION = 5.0;
};
name = Release;
};
@@ -1343,7 +1337,6 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SUPPORTED_PLATFORMS = macosx;
- SWIFT_VERSION = 4.0;
};
name = Debug;
};
@@ -1369,7 +1362,6 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = macosx;
SUPPORTED_PLATFORMS = macosx;
- SWIFT_VERSION = 4.0;
};
name = Release;
};
@@ -1402,7 +1394,6 @@
SDKROOT = macosx;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = macosx;
- SWIFT_VERSION = 4.0;
};
name = Debug;
};
@@ -1435,7 +1426,6 @@
SDKROOT = macosx;
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = macosx;
- SWIFT_VERSION = 4.0;
};
name = Release;
};
@@ -1458,7 +1448,6 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
- SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 11.3;
};
@@ -1483,7 +1472,6 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = appletvos;
SUPPORTED_PLATFORMS = "appletvsimulator appletvos";
- SWIFT_VERSION = 4.0;
TARGETED_DEVICE_FAMILY = 3;
TVOS_DEPLOYMENT_TARGET = 11.3;
};
diff --git a/Sources/Extensions/UIView+PinLayout.swift b/Sources/Extensions/UIView+PinLayout.swift
index 831f9601..2f551234 100644
--- a/Sources/Extensions/UIView+PinLayout.swift
+++ b/Sources/Extensions/UIView+PinLayout.swift
@@ -122,14 +122,8 @@ extension UIView: AutoSizeCalculable {
}
public func setAutoSizingRect(_ rect: CGRect, margins: PEdgeInsets) {
- #if os(tvOS)
- let rectWithMargins = UIEdgeInsetsInsetRect(rect, margins)
- #else
- let rectWithMargins = rect.inset(by: margins)
- #endif
-
self.autoSizingRect = Coordinates.adjustRectToDisplayScale(rect)
- self.autoSizingRectWithMargins = Coordinates.adjustRectToDisplayScale(rectWithMargins)
+ self.autoSizingRectWithMargins = Coordinates.adjustRectToDisplayScale(rect.inset(by: margins))
}
public func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize {
From 457b17b60b5bea70c53ef3ffd9194437f38c81ab Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Wed, 17 Jun 2020 11:41:28 -0400
Subject: [PATCH 15/23] Specify swift version in podspec
---
PinLayout.podspec | 1 +
1 file changed, 1 insertion(+)
diff --git a/PinLayout.podspec b/PinLayout.podspec
index 32d192dd..f37c9e4b 100644
--- a/PinLayout.podspec
+++ b/PinLayout.podspec
@@ -16,6 +16,7 @@ Pod::Spec.new do |spec|
spec.author = { "Luc Dion" => "luc_dion@yahoo.com" }
spec.source = { :git => "https://github.com/layoutBox/PinLayout.git", :tag => "#{spec.version}" }
spec.source_files = "Sources/**/*.swift"
+ spec.swift_version = '5.0'
spec.ios.deployment_target = '8.0'
spec.ios.frameworks = 'Foundation', 'CoreGraphics', 'UIKit'
From a9c4ae863aafb47b74f8c314ac59dc36e72d371d Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Thu, 25 Jun 2020 16:53:59 -0400
Subject: [PATCH 16/23] Put setRect in a else condition
---
Sources/Impl/PinLayout+Layouting.swift | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/Sources/Impl/PinLayout+Layouting.swift b/Sources/Impl/PinLayout+Layouting.swift
index 36f078b8..e9aacb61 100644
--- a/Sources/Impl/PinLayout+Layouting.swift
+++ b/Sources/Impl/PinLayout+Layouting.swift
@@ -137,15 +137,9 @@ extension PinLayout {
if Pin.autoSizingInProgress, let autoSizeCalculable = view as? AutoSizeCalculable {
let marginInsets = PEdgeInsets(top: -_marginTop, left: -_marginLeft, bottom: -_marginBottom, right: -_marginRight)
autoSizeCalculable.setAutoSizingRect(newRect, margins: marginInsets)
+ } else {
+ view.setRect(newRect, keepTransform: keepTransform)
}
-
- /*
- To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
- view's transform (UIView.transform).
- By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep
- the view's transform. So view's transforms won't be affected/altered by PinLayout.
- */
- view.setRect(newRect, keepTransform: keepTransform)
}
private func handlePinEdges() {
From c0890ebe9d716fb6e9ef232308b306e8f5853506 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Thu, 25 Jun 2020 23:19:28 -0400
Subject: [PATCH 17/23] Add AutoSizing Example
---
.../PinLayoutSample.xcodeproj/project.pbxproj | 28 ++++++++
.../UI/Common/ContentService.swift | 41 +++++++++++
.../UI/Common/ProxyWrapper.swift | 31 +++++++++
.../AutoSizing/AutoSizingContainerView.swift | 68 +++++++++++++++++++
.../Examples/AutoSizing/AutoSizingView.swift | 54 +++++++++++++++
.../AutoSizing/AutoSizingViewController.swift | 39 +++++++++++
.../UI/Menu/MenuViewController.swift | 4 ++
7 files changed, 265 insertions(+)
create mode 100644 Example/PinLayoutSample/UI/Common/ContentService.swift
create mode 100644 Example/PinLayoutSample/UI/Common/ProxyWrapper.swift
create mode 100644 Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingContainerView.swift
create mode 100644 Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingView.swift
create mode 100644 Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingViewController.swift
diff --git a/Example/PinLayoutSample.xcodeproj/project.pbxproj b/Example/PinLayoutSample.xcodeproj/project.pbxproj
index 05eb9d88..0c1e833b 100644
--- a/Example/PinLayoutSample.xcodeproj/project.pbxproj
+++ b/Example/PinLayoutSample.xcodeproj/project.pbxproj
@@ -41,6 +41,11 @@
24F246141FA8D57100B6332E /* UIImageView+Download.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F246131FA8D57100B6332E /* UIImageView+Download.swift */; };
24F75B5B1EE5644E008DB567 /* IntroView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F75B591EE5644E008DB567 /* IntroView.swift */; };
24F75B5C1EE5644E008DB567 /* IntroViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F75B5A1EE5644E008DB567 /* IntroViewController.swift */; };
+ C892FA1924A5821E0086A75E /* AutoSizingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C892FA1824A5821E0086A75E /* AutoSizingViewController.swift */; };
+ C892FA1B24A5822B0086A75E /* AutoSizingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C892FA1A24A5822B0086A75E /* AutoSizingView.swift */; };
+ C892FA1D24A584010086A75E /* ContentService.swift in Sources */ = {isa = PBXBuildFile; fileRef = C892FA1C24A584010086A75E /* ContentService.swift */; };
+ C892FA1F24A597FA0086A75E /* AutoSizingContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C892FA1E24A597FA0086A75E /* AutoSizingContainerView.swift */; };
+ C892FA2124A598170086A75E /* ProxyWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C892FA2024A598170086A75E /* ProxyWrapper.swift */; };
DF390898211900320049FD56 /* AnimationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF390897211900320049FD56 /* AnimationsView.swift */; };
DF39089A211900480049FD56 /* AnimationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF390899211900480049FD56 /* AnimationsViewController.swift */; };
DF4C1AA4205AEDFC00DED50B /* SafeAreaView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF4C1AA0205AEDFC00DED50B /* SafeAreaView.swift */; };
@@ -148,6 +153,11 @@
24F75B5A1EE5644E008DB567 /* IntroViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntroViewController.swift; sourceTree = ""; };
A35A00E6536E49A548E763E6 /* Pods-PinLayoutSample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutSample.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-PinLayoutSample/Pods-PinLayoutSample.debug.xcconfig"; sourceTree = ""; };
C589624E868FCB20F7C10918 /* Pods-PinLayoutSample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-PinLayoutSample.release.xcconfig"; path = "../Pods/Target Support Files/Pods-PinLayoutSample/Pods-PinLayoutSample.release.xcconfig"; sourceTree = ""; };
+ C892FA1824A5821E0086A75E /* AutoSizingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoSizingViewController.swift; sourceTree = ""; };
+ C892FA1A24A5822B0086A75E /* AutoSizingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoSizingView.swift; sourceTree = ""; };
+ C892FA1C24A584010086A75E /* ContentService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentService.swift; sourceTree = ""; };
+ C892FA1E24A597FA0086A75E /* AutoSizingContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoSizingContainerView.swift; sourceTree = ""; };
+ C892FA2024A598170086A75E /* ProxyWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProxyWrapper.swift; sourceTree = ""; };
DF390897211900320049FD56 /* AnimationsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimationsView.swift; path = PinLayoutSample/UI/Examples/Animations/AnimationsView.swift; sourceTree = SOURCE_ROOT; };
DF390899211900480049FD56 /* AnimationsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationsViewController.swift; sourceTree = ""; };
DF4C1AA0205AEDFC00DED50B /* SafeAreaView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafeAreaView.swift; sourceTree = ""; };
@@ -236,6 +246,7 @@
DFD31B9D212EE4D600566CA4 /* TableViewReadableContent */,
24D18D181F3DECD6008129EF /* IntroRTL */,
2416376F1F8E4BC200EE703A /* IntroObjectiveC */,
+ C892FA1124A582050086A75E /* AutoSizing */,
24CD1E8D1F8E4B0A00C3A54D /* PinLayoutSample-Bridging-Header.h */,
);
path = Examples;
@@ -251,6 +262,8 @@
24F246131FA8D57100B6332E /* UIImageView+Download.swift */,
DFD27840211B1A700056BD93 /* UINavigationController+Orientation.swift */,
DFD27847211B1D090056BD93 /* UITabBarController+Orientation.swift */,
+ C892FA1C24A584010086A75E /* ContentService.swift */,
+ C892FA2024A598170086A75E /* ProxyWrapper.swift */,
);
path = Common;
sourceTree = "";
@@ -395,6 +408,16 @@
path = Intro;
sourceTree = "";
};
+ C892FA1124A582050086A75E /* AutoSizing */ = {
+ isa = PBXGroup;
+ children = (
+ C892FA1824A5821E0086A75E /* AutoSizingViewController.swift */,
+ C892FA1A24A5822B0086A75E /* AutoSizingView.swift */,
+ C892FA1E24A597FA0086A75E /* AutoSizingContainerView.swift */,
+ );
+ path = AutoSizing;
+ sourceTree = "";
+ };
DF3908912118FFF20049FD56 /* Animations */ = {
isa = PBXGroup;
children = (
@@ -657,10 +680,12 @@
24F75B5C1EE5644E008DB567 /* IntroViewController.swift in Sources */,
241637741F8E4BC200EE703A /* IntroObjectiveCViewController.m in Sources */,
DF390898211900320049FD56 /* AnimationsView.swift in Sources */,
+ C892FA2124A598170086A75E /* ProxyWrapper.swift in Sources */,
2439CC541E665C6B003326FB /* RelativeView.swift in Sources */,
2439CC551E665C6B003326FB /* RelativeViewController.swift in Sources */,
247157941F87BD680003424F /* UIEdgeInsets+PinLayout.swift in Sources */,
24D18D1E1F3DED0D008129EF /* IntroRTLViewController.swift in Sources */,
+ C892FA1F24A597FA0086A75E /* AutoSizingContainerView.swift in Sources */,
DFEAF74C20C9649F00E33147 /* WrapContentViewController.swift in Sources */,
24F246121FA8D4D100B6332E /* HouseCell.swift in Sources */,
DF4C1AAE205AF78A00DED50B /* SafeAreaAndMarginsViewController.swift in Sources */,
@@ -677,6 +702,7 @@
24CB999C1F29059B004EA7FB /* AdjustToContainerView.swift in Sources */,
2497CFED1EF40B9100DFD13B /* FormView.swift in Sources */,
24F75B5B1EE5644E008DB567 /* IntroView.swift in Sources */,
+ C892FA1B24A5822B0086A75E /* AutoSizingView.swift in Sources */,
DF4C1AA5205AEDFC00DED50B /* SafeAreaViewController.swift in Sources */,
DFEAF74A20C9648A00E33147 /* WrapContentView.swift in Sources */,
249EFE431E64FAFE00165E39 /* AppDelegate.swift in Sources */,
@@ -689,9 +715,11 @@
24F246111FA8D4D100B6332E /* CollectionViewExampleViewController.swift in Sources */,
2439CC531E665C6B003326FB /* BetweenViewController.swift in Sources */,
DF4C1AA4205AEDFC00DED50B /* SafeAreaView.swift in Sources */,
+ C892FA1924A5821E0086A75E /* AutoSizingViewController.swift in Sources */,
241637771F8E4F9100EE703A /* IntroObjectiveCView.m in Sources */,
24CB99A01F290664004EA7FB /* ChoiceSelectorView.swift in Sources */,
249326891EEEEE3D00BCB814 /* Stylesheet.swift in Sources */,
+ C892FA1D24A584010086A75E /* ContentService.swift in Sources */,
DFD31BA0212EE4F200566CA4 /* TableViewReadableContentView.swift in Sources */,
DF39089A211900480049FD56 /* AnimationsViewController.swift in Sources */,
2439CC521E665C6B003326FB /* BetweenView.swift in Sources */,
diff --git a/Example/PinLayoutSample/UI/Common/ContentService.swift b/Example/PinLayoutSample/UI/Common/ContentService.swift
new file mode 100644
index 00000000..65955d25
--- /dev/null
+++ b/Example/PinLayoutSample/UI/Common/ContentService.swift
@@ -0,0 +1,41 @@
+import UIKit
+
+class ContentService {
+ static let shared = ContentService()
+
+ private init() {}
+
+ func fetchText(numberOfParagraph: Int = 1, completionHandler: ((Result<[String], Error>) -> Void)?) {
+ URLSession.shared.dataTask(with: URL(string: "https://baconipsum.com/api/?type=all-meat¶s=\(numberOfParagraph)&start-with-lorem=1")!) { data, _, error in
+ guard let data = data, error == nil,
+ let paragraphs = try? JSONDecoder().decode([String].self, from: data)
+ else {
+ DispatchQueue.main.async {
+ completionHandler?(Result<[String], Error>.failure(error!))
+ }
+ return
+ }
+
+ DispatchQueue.main.async {
+ completionHandler?(Result<[String], Error>.success(paragraphs))
+ }
+ }.resume()
+ }
+
+ func fetchImage(width: Int, height: Int, completionHandler: ((Result) -> Void)?) {
+ URLSession.shared.dataTask(with: URL(string: "https://baconmockup.com/\(width)/\(height)")!) { data, _, error in
+ guard let data = data, error == nil,
+ let image = UIImage(data: data)
+ else {
+ DispatchQueue.main.async {
+ completionHandler?(Result.failure(error!))
+ }
+ return
+ }
+
+ DispatchQueue.main.async {
+ completionHandler?(Result.success(image))
+ }
+ }.resume()
+ }
+}
diff --git a/Example/PinLayoutSample/UI/Common/ProxyWrapper.swift b/Example/PinLayoutSample/UI/Common/ProxyWrapper.swift
new file mode 100644
index 00000000..9752998b
--- /dev/null
+++ b/Example/PinLayoutSample/UI/Common/ProxyWrapper.swift
@@ -0,0 +1,31 @@
+import Foundation
+
+@propertyWrapper
+public struct Proxy {
+ private let keyPath: ReferenceWritableKeyPath
+
+ public init(_ keyPath: ReferenceWritableKeyPath) {
+ self.keyPath = keyPath
+ }
+
+ public var wrappedValue: Value {
+ get { fatalError() }
+ set { fatalError() }
+ }
+
+ public static subscript(
+ _enclosingInstance observed: EnclosingSelf,
+ wrapped wrappedKeyPath: ReferenceWritableKeyPath,
+ storage storageKeyPath: ReferenceWritableKeyPath
+ ) -> Value {
+ get {
+ let storageValue = observed[keyPath: storageKeyPath]
+ let value = observed[keyPath: storageValue.keyPath]
+ return value
+ }
+ set {
+ let storageValue = observed[keyPath: storageKeyPath]
+ observed[keyPath: storageValue.keyPath] = newValue
+ }
+ }
+}
diff --git a/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingContainerView.swift b/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingContainerView.swift
new file mode 100644
index 00000000..40048996
--- /dev/null
+++ b/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingContainerView.swift
@@ -0,0 +1,68 @@
+import UIKit
+
+final class AutoSizingContainerView: UIView {
+ private let imageView = UIImageView()
+ private let firstTextLabel = UILabel()
+ private let secondTextLabel = UILabel()
+
+ private let margin: CGFloat = 10
+
+ @Proxy(\AutoSizingContainerView.imageView.image)
+ var image: UIImage? {
+ didSet {
+ setNeedsLayout()
+ }
+ }
+
+ @Proxy(\AutoSizingContainerView.firstTextLabel.text)
+ var firstText: String? {
+ didSet {
+ setNeedsLayout()
+ }
+ }
+
+ @Proxy(\AutoSizingContainerView.secondTextLabel.text)
+ var secondText: String? {
+ didSet {
+ setNeedsLayout()
+ }
+ }
+
+ init() {
+ super.init(frame: CGRect.zero)
+ configureView()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ private func configureView() {
+ imageView.clipsToBounds = true
+ imageView.contentMode = .scaleAspectFill
+ addSubview(imageView)
+
+ firstTextLabel.numberOfLines = 0
+ firstTextLabel.backgroundColor = UIColor.orange.withAlphaComponent(0.3)
+ addSubview(firstTextLabel)
+
+ secondTextLabel.numberOfLines = 0
+ secondTextLabel.backgroundColor = UIColor.green.withAlphaComponent(0.3)
+ addSubview(secondTextLabel)
+ }
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+ performLayout()
+ }
+
+ private func performLayout() {
+ imageView.pin.top().horizontally().sizeToFit(.width).margin(margin)
+ firstTextLabel.pin.below(of: imageView).horizontally().sizeToFit(.width).margin(margin)
+ secondTextLabel.pin.below(of: firstTextLabel).horizontally().sizeToFit(.width).margin(margin)
+ }
+
+ override func sizeThatFits(_ size: CGSize) -> CGSize {
+ autoSizeThatFits(size, layoutClosure: performLayout)
+ }
+}
diff --git a/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingView.swift b/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingView.swift
new file mode 100644
index 00000000..a248d1be
--- /dev/null
+++ b/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingView.swift
@@ -0,0 +1,54 @@
+import UIKit
+import PinLayout
+
+final class AutoSizingView: UIView {
+ private let scrollView = UIScrollView()
+ private let containerView = AutoSizingContainerView()
+
+ private let margin: CGFloat = 30
+
+ init() {
+ super.init(frame: CGRect.zero)
+ configureView()
+ }
+
+ required init?(coder: NSCoder) {
+ fatalError("init(coder:) has not been implemented")
+ }
+
+ private func configureView() {
+ backgroundColor = .white
+
+ scrollView.alwaysBounceVertical = true
+ addSubview(scrollView)
+
+ containerView.backgroundColor = UIColor.lightGray.withAlphaComponent(0.3)
+ scrollView.addSubview(containerView)
+ }
+
+ func updateImage(_ image: UIImage?) {
+ containerView.image = image
+ setNeedsLayout()
+ }
+
+ func updateTexts(firstText: String?, secondText: String?) {
+ containerView.firstText = firstText
+ containerView.secondText = secondText
+ setNeedsLayout()
+ }
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+ performLayout()
+ didPerformLayout()
+ }
+
+ private func performLayout() {
+ scrollView.pin.all()
+ containerView.pin.top(margin).horizontally(margin).sizeToFit(.width)
+ }
+
+ private func didPerformLayout() {
+ scrollView.contentSize = CGSize(width: bounds.width, height: containerView.frame.maxY + margin)
+ }
+}
diff --git a/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingViewController.swift b/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingViewController.swift
new file mode 100644
index 00000000..408c9f73
--- /dev/null
+++ b/Example/PinLayoutSample/UI/Examples/AutoSizing/AutoSizingViewController.swift
@@ -0,0 +1,39 @@
+import UIKit
+
+class AutoSizingViewController: UIViewController {
+ private var mainView: AutoSizingView {
+ return self.view as! AutoSizingView
+ }
+
+ override func loadView() {
+ self.view = AutoSizingView()
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ configureNavigationBar()
+ }
+
+ override func viewWillAppear(_ animated: Bool) {
+ super.viewWillAppear(animated)
+ randomizeContent()
+ }
+
+ private func configureNavigationBar() {
+ navigationItem.title = "AutoSizing"
+ navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Randomize", style: .plain, target: self, action: #selector(randomizeContent))
+ }
+
+ @objc
+ private func randomizeContent() {
+ ContentService.shared.fetchText(numberOfParagraph: 2) { [weak self] (result) in
+ guard let strongSelf = self, case let .success(paragraphs) = result else { return }
+ strongSelf.mainView.updateTexts(firstText: paragraphs[0], secondText: paragraphs[1])
+ }
+
+ ContentService.shared.fetchImage(width: Int.random(in: 200..<500), height: Int.random(in: 200..<500)) { [weak self] (result) in
+ guard let strongSelf = self, case let .success(image) = result else { return }
+ strongSelf.mainView.updateImage(image)
+ }
+ }
+}
diff --git a/Example/PinLayoutSample/UI/Menu/MenuViewController.swift b/Example/PinLayoutSample/UI/Menu/MenuViewController.swift
index ff8d2bbf..4179aabf 100644
--- a/Example/PinLayoutSample/UI/Menu/MenuViewController.swift
+++ b/Example/PinLayoutSample/UI/Menu/MenuViewController.swift
@@ -34,6 +34,7 @@ enum PageType: Int {
case tableViewWithReadable
case introRTL
case introObjC
+ case autoSizing
case count
@@ -53,6 +54,7 @@ enum PageType: Int {
case .tableViewWithReadable: return "UITableView using readableMargins"
case .introRTL: return "Right-to-left Language Support"
case .introObjC: return "Objective-C PinLayout Example"
+ case .autoSizing: return "Auto Sizing"
case .count: return ""
}
}
@@ -90,6 +92,8 @@ enum PageType: Int {
return IntroRTLViewController(pageType: self)
case .introObjC:
return IntroObjectiveCViewController()
+ case .autoSizing:
+ return AutoSizingViewController()
case .count:
return UIViewController()
}
From 83d420d75c5cf7c1d5de195d76b43de09d26e58d Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Fri, 26 Jun 2020 08:23:13 -0400
Subject: [PATCH 18/23] Add documentation
---
README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 52 insertions(+)
diff --git a/README.md b/README.md
index e2728626..f8ded69b 100644
--- a/README.md
+++ b/README.md
@@ -1477,6 +1477,58 @@ This example centered horizontally the view B in the space remaining at the righ
+
+## Automatic Sizing
+Sizing views as part of the manual layout process is made with `sizeThatFits(_ size: CGSize)` where a view returns its ideal size given his parent size. Implementing sizing code has always been cumbersome because you always end up writing the same code twice, a first time for the layout and the second time for sizing. Sizing usually use the same rules layout does but implemented slightly differently because no subview `frame` should be mutated during sizing. Since `PinLayout` already takes care of the layout, it makes perfect sense to leverage it's layout engine to compute sizing.
+
+###### Traditional example:
+```swift
+ override func layoutSubviews() {
+ super.layoutSubviews()
+ scrollView.pin.all()
+ imageView.pin.top().horizontally().sizeToFit(.width).margin(margin)
+ textLabel.pin.below(of: imageView).horizontally().sizeToFit(.width).margin(margin)
+ scrollView.contentSize = CGSize(width: scrollView.bounds.width, height: textLabel.frame.maxY + margin)
+ }
+
+ override func sizeThatFits(_ size: CGSize) -> CGSize {
+ let availableSize = CGSize(width: size.width, height: CGFloat.greatestFiniteMagnitude)
+ return CGSize(width: size.width, height:
+ imageView.sizeThatFits(availableSize).height +
+ margin +
+ textLabel.sizeThatFits(availableSize).height +
+ margin
+ )
+ }
+```
+
+###### Usage examples:
+```swift
+ override func layoutSubviews() {
+ super.layoutSubviews()
+ performLayout()
+ didPerformLayout()
+ }
+
+ private func performLayout() {
+ scrollView.pin.all()
+ imageView.pin.top().horizontally().sizeToFit(.width).margin(margin)
+ textLabel.pin.below(of: imageView).horizontally().sizeToFit(.width).margin(margin)
+ }
+
+ private func didPerformLayout() {
+ scrollView.contentSize = CGSize(width: scrollView.bounds.width, height: textLabel.frame.maxY + margin)
+ }
+
+ override func sizeThatFits(_ size: CGSize) -> CGSize {
+ autoSizeThatFits(size, layoutClosure: performLayout)
+ }
+```
+
+By calling `autoSizeThatFits` with the given available size and a layout closure, any layouting performed by PinLayout in that closure will be computed without affecting any subview's `frame` in the view hierarchy. On the other hand, any non PinLayout related code will also be executed, for that reason, it is really important to isolate your layout code in a separate function to avoid any side effect from occuring during sizing, like setting the scroll view's content size in the above exemple or assigning `itemSize` in collection view layout for exemple. That kind of code that depends on the layout should only be executed when `layoutSubviews()` is called as part of a normal layout pass.
+
+The resulting size also takes into account the margins applied on subviews, even on the bottom and trailing sides. Automatic sizing makes it really easy to write your layout logic once and add proper sizing behavior with virtually no additional effort.
+
## UIView's transforms
From bba716a55ed9119007cb9350690c420156a8ae16 Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Fri, 26 Jun 2020 08:38:25 -0400
Subject: [PATCH 19/23] Move exemple in a more logical order
---
Example/PinLayoutSample/UI/Menu/MenuViewController.swift | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/Example/PinLayoutSample/UI/Menu/MenuViewController.swift b/Example/PinLayoutSample/UI/Menu/MenuViewController.swift
index 4179aabf..3ed89167 100644
--- a/Example/PinLayoutSample/UI/Menu/MenuViewController.swift
+++ b/Example/PinLayoutSample/UI/Menu/MenuViewController.swift
@@ -31,10 +31,10 @@ enum PageType: Int {
case between
case form
case wrapContent
+ case autoSizing
case tableViewWithReadable
case introRTL
case introObjC
- case autoSizing
case count
@@ -51,10 +51,10 @@ enum PageType: Int {
case .between: return "Between Example"
case .form: return "Form Example"
case .wrapContent: return "wrapContent Example"
+ case .autoSizing: return "Auto Sizing"
case .tableViewWithReadable: return "UITableView using readableMargins"
case .introRTL: return "Right-to-left Language Support"
case .introObjC: return "Objective-C PinLayout Example"
- case .autoSizing: return "Auto Sizing"
case .count: return ""
}
}
@@ -86,14 +86,14 @@ enum PageType: Int {
return FormViewController(pageType: self)
case .wrapContent:
return WrapContentViewController(pageType: self)
+ case .autoSizing:
+ return AutoSizingViewController()
case .tableViewWithReadable:
return TableViewReadableContentViewController(pageType: self)
case .introRTL:
return IntroRTLViewController(pageType: self)
case .introObjC:
return IntroObjectiveCViewController()
- case .autoSizing:
- return AutoSizingViewController()
case .count:
return UIViewController()
}
From 142acdf5bf3de3fc5ee4bf9149414bb2358c8b9b Mon Sep 17 00:00:00 2001
From: Antoine Lamy
Date: Fri, 26 Jun 2020 08:46:20 -0400
Subject: [PATCH 20/23] Readme adjustments
---
README.md | 11 +++++++----
docs/pinlayout_exampleapp_automatic_sizing.png | Bin 0 -> 713024 bytes
2 files changed, 7 insertions(+), 4 deletions(-)
create mode 100644 docs/pinlayout_exampleapp_automatic_sizing.png
diff --git a/README.md b/README.md
index f8ded69b..29a8646b 100644
--- a/README.md
+++ b/README.md
@@ -72,6 +72,7 @@ Extremely Fast views layouting without auto layout. No magic, pure code, full co
* [safeArea, readable and layout margins](#safeAreaInsets)
* [WrapContent](#wrapContent)
* [justify, align](#justify_align)
+ * [Automatic sizing](#automatic_sizing)
* [UIView's transforms](#uiview_transform)
* [Warnings](#warnings)
* [Animations using PinLayout](#animations)
@@ -1477,7 +1478,7 @@ This example centered horizontally the view B in the space remaining at the righ
-
+
## Automatic Sizing
Sizing views as part of the manual layout process is made with `sizeThatFits(_ size: CGSize)` where a view returns its ideal size given his parent size. Implementing sizing code has always been cumbersome because you always end up writing the same code twice, a first time for the layout and the second time for sizing. Sizing usually use the same rules layout does but implemented slightly differently because no subview `frame` should be mutated during sizing. Since `PinLayout` already takes care of the layout, it makes perfect sense to leverage it's layout engine to compute sizing.
@@ -1504,20 +1505,20 @@ Sizing views as part of the manual layout process is made with `sizeThatFits(_ s
###### Usage examples:
```swift
- override func layoutSubviews() {
+ override func layoutSubviews() {
super.layoutSubviews()
performLayout()
didPerformLayout()
}
private func performLayout() {
- scrollView.pin.all()
+ scrollView.pin.all()
imageView.pin.top().horizontally().sizeToFit(.width).margin(margin)
textLabel.pin.below(of: imageView).horizontally().sizeToFit(.width).margin(margin)
}
private func didPerformLayout() {
- scrollView.contentSize = CGSize(width: scrollView.bounds.width, height: textLabel.frame.maxY + margin)
+ scrollView.contentSize = CGSize(width: scrollView.bounds.width, height: textLabel.frame.maxY + margin)
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
@@ -1801,6 +1802,7 @@ Included examples:
* Example showing how to animate with PinLayout.
* Example using [`pin.safeArea`, `pin.readableMargins` and `pin.layoutMargins`](#safeAreaInsets)
* Example using [`wrapContent()`](#wrapContent)
+* Example using [`autoSizeThatFits`](#automatic_sizing)
* Example showing right-to-left (RTL) language support.
* Example showing a simple form example
* Example showing Relative Edges layout.
@@ -1817,6 +1819,7 @@ Included examples:
+
diff --git a/docs/pinlayout_exampleapp_automatic_sizing.png b/docs/pinlayout_exampleapp_automatic_sizing.png
new file mode 100644
index 0000000000000000000000000000000000000000..77157fba9d258ae47eb5f91f37d55ba21e78807a
GIT binary patch
literal 713024
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 |