Skip to content

Commit 089ebe9

Browse files
committed
Working prototype
1 parent 9e3b4f8 commit 089ebe9

File tree

6 files changed

+80
-14
lines changed

6 files changed

+80
-14
lines changed

Example/PinLayoutSample/UI/Examples/AdjustToContainer/Subviews/ChoiceSelectorView.swift

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,13 @@ class ChoiceSelectorView: UIView {
4646

4747
override func layoutSubviews() {
4848
super.layoutSubviews()
49-
_ = layout()
49+
layout()
5050
}
5151

52-
override func sizeThatFits(_ size: CGSize) -> CGSize {
53-
// 1) Set the width to the specified width
54-
self.pin.width(size.width)
55-
56-
// 2) Layout the contentView's controls
57-
return layout()
58-
}
59-
60-
private func layout() -> CGSize {
52+
private func layout() {
6153
let margin: CGFloat = 12
6254

63-
if frame.width > 500 {
55+
if bounds.width > 500 {
6456
// The UISegmentedControl is at the top-right corner and the label takes the remaining horizontal space.
6557
segmentedControl.pin.top().right().margin(margin)
6658
textLabel.pin.top().left().before(of: segmentedControl).margin(margin).sizeToFit(.width)
@@ -69,7 +61,9 @@ class ChoiceSelectorView: UIView {
6961
textLabel.pin.top().horizontally().margin(margin).sizeToFit(.width)
7062
segmentedControl.pin.below(of: textLabel).right().margin(margin)
7163
}
64+
}
7265

73-
return CGSize(width: frame.width, height: max(textLabel.frame.maxY, segmentedControl.frame.maxY) + margin)
66+
override func sizeThatFits(_ size: CGSize) -> CGSize {
67+
return autoSizeThatFits(size) { layout() }
7468
}
7569
}

PinLayout.xcodeproj/project.pbxproj

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@
4444
C80435D720D08A2C00EB1BD7 /* SizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */; };
4545
C80435D820D08B7300EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; };
4646
C80435D920D08B7400EB1BD7 /* Layoutable+PinLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */; };
47+
C8291E41247A242600E95886 /* AutoSizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8291E40247A242600E95886 /* AutoSizeCalculable.swift */; };
48+
C8291E42247A243900E95886 /* AutoSizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8291E40247A242600E95886 /* AutoSizeCalculable.swift */; };
49+
C8291E43247A243900E95886 /* AutoSizeCalculable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8291E40247A242600E95886 /* AutoSizeCalculable.swift */; };
4750
C82DC20C20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; };
4851
C82DC20D20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; };
4952
C82DC20E20CE9F6800B7ACF5 /* Layoutable.swift in Sources */ = {isa = PBXBuildFile; fileRef = C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */; };
@@ -230,6 +233,7 @@
230233
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 = "<group>"; };
231234
C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SizeCalculable.swift; sourceTree = "<group>"; };
232235
C80435D420D0898000EB1BD7 /* Layoutable+PinLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Layoutable+PinLayout.swift"; sourceTree = "<group>"; };
236+
C8291E40247A242600E95886 /* AutoSizeCalculable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoSizeCalculable.swift; sourceTree = "<group>"; };
233237
C82DC20B20CE9F6800B7ACF5 /* Layoutable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Layoutable.swift; sourceTree = "<group>"; };
234238
C83588BF20DBC5E600D6E8F9 /* CALayerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CALayerSpec.swift; sourceTree = "<group>"; };
235239
C83600A520E2949200A3D891 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; usesTabs = 1; };
@@ -375,6 +379,7 @@
375379
DF702D8C20D33BA90062045C /* PinLayout+Size.swift */,
376380
DF702D8B20D33BA90062045C /* PinLayout+WrapContent.swift */,
377381
C80435D220D0891C00EB1BD7 /* SizeCalculable.swift */,
382+
C8291E40247A242600E95886 /* AutoSizeCalculable.swift */,
378383
DFF222CC20B999BD00AC2A84 /* Types.swift */,
379384
DF702DA720D33D2A0062045C /* Extensions */,
380385
DFA06B031E8B38B300B6D5E7 /* Impl */,
@@ -418,7 +423,6 @@
418423
DE878C8BA276883C90524382 /* Pods-PinLayoutTests-tvOS.debug.xcconfig */,
419424
89672C5CCF1F123104855629 /* Pods-PinLayoutTests-tvOS.release.xcconfig */,
420425
);
421-
name = Pods;
422426
path = Pods;
423427
sourceTree = "<group>";
424428
};
@@ -895,6 +899,7 @@
895899
DF46F686212442EF0055B081 /* PEdgeInsets+Operators.swift in Sources */,
896900
DF702DA520D33CFA0062045C /* PinLayout+Layouting.swift in Sources */,
897901
DF702DA620D33CFA0062045C /* PinLayout+Warning.swift in Sources */,
902+
C8291E43247A243900E95886 /* AutoSizeCalculable.swift in Sources */,
898903
DF702DAF20D33D6A0062045C /* UIView+PinLayout.swift in Sources */,
899904
DF702D9D20D33CF20062045C /* PinLayout.swift in Sources */,
900905
);
@@ -927,6 +932,7 @@
927932
DF46F684212442EE0055B081 /* PEdgeInsets+Operators.swift in Sources */,
928933
24949A2E1EF69474003643D3 /* Filters.swift in Sources */,
929934
DFB3ECB12061602F005F226B /* PinSafeArea.swift in Sources */,
935+
C8291E41247A242600E95886 /* AutoSizeCalculable.swift in Sources */,
930936
DF702DAB20D33D660062045C /* UIView+PinLayout.swift in Sources */,
931937
C80435D520D0898000EB1BD7 /* Layoutable+PinLayout.swift in Sources */,
932938
);
@@ -1018,6 +1024,7 @@
10181024
DF46F685212442EE0055B081 /* PEdgeInsets+Operators.swift in Sources */,
10191025
DF702DA220D33CF90062045C /* PinLayout+Layouting.swift in Sources */,
10201026
DF702DA320D33CF90062045C /* PinLayout+Warning.swift in Sources */,
1027+
C8291E42247A243900E95886 /* AutoSizeCalculable.swift in Sources */,
10211028
DF702DAD20D33D6A0062045C /* UIView+PinLayout.swift in Sources */,
10221029
DF702D9920D33CF10062045C /* PinLayout.swift in Sources */,
10231030
);

Sources/AutoSizeCalculable.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#if os(iOS) || os(tvOS)
2+
import UIKit
3+
#else
4+
import AppKit
5+
#endif
6+
7+
public protocol AutoSizeCalculable {
8+
var autoSizingRect: CGRect? { get set }
9+
var autoSizingRectWithMargins: CGRect? { get set }
10+
11+
func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize
12+
}

Sources/Extensions/UIView+PinLayout.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ extension UIView: Layoutable, SizeCalculable {
3838
}
3939

4040
public func getRect(keepTransform: Bool) -> CGRect {
41+
guard !Pin.autoSizingInProgress || autoSizingRect == nil else { return autoSizingRect ?? CGRect.zero }
42+
4143
if keepTransform {
4244
/*
4345
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 {
5961
public func setRect(_ rect: CGRect, keepTransform: Bool) {
6062
let adjustedRect = Coordinates<View>.adjustRectToDisplayScale(rect)
6163

64+
guard !Pin.autoSizingInProgress else {
65+
autoSizingRect = adjustedRect
66+
return
67+
}
68+
6269
if keepTransform {
6370
/*
6471
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 {
95102
}
96103
}
97104

105+
extension UIView: AutoSizeCalculable {
106+
private struct pinlayoutAssociatedKeys {
107+
static var pinlayoutAutoSizingRect = UnsafeMutablePointer<Int8>.allocate(capacity: 1)
108+
static var pinlayoutAutoSizingRectWithMargins = UnsafeMutablePointer<Int8>.allocate(capacity: 1)
109+
}
110+
111+
public var autoSizingRect: CGRect? {
112+
get {
113+
return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRect) as? CGRect
114+
}
115+
set {
116+
objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRect, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
117+
}
118+
}
119+
120+
public var autoSizingRectWithMargins: CGRect? {
121+
get {
122+
return objc_getAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRectWithMargins) as? CGRect
123+
}
124+
set {
125+
objc_setAssociatedObject(self, &pinlayoutAssociatedKeys.pinlayoutAutoSizingRectWithMargins, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
126+
}
127+
}
128+
129+
public func autoSizeThatFits(_ size: CGSize, layoutClosure: () -> Void) -> CGSize {
130+
Pin.autoSizingInProgress = true
131+
autoSizingRect = CGRect(origin: CGPoint.zero, size: size)
132+
layoutClosure()
133+
134+
let boundingRect = subviews.compactMap({ $0.autoSizingRectWithMargins }).reduce(CGRect.zero) { (result: CGRect, autoSizingRect: CGRect) -> CGRect in
135+
return result.union(autoSizingRect)
136+
}
137+
138+
Pin.autoSizingInProgress = false
139+
return boundingRect.size
140+
}
141+
}
142+
98143
#endif

Sources/Impl/PinLayout+Layouting.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,13 @@ extension PinLayout {
133133
if !validateComputedHeight(newRect.size.height) {
134134
newRect.size.height = view.getRect(keepTransform: keepTransform).height
135135
}
136-
136+
137+
if Pin.autoSizingInProgress, var autoSizeCalculable = view as? AutoSizeCalculable {
138+
let marginInsets = UIEdgeInsets(top: -_marginTop, left: -_marginLeft, bottom: -_marginBottom, right: -_marginRight)
139+
let rectWithMargins = newRect.inset(by: marginInsets)
140+
autoSizeCalculable.autoSizingRectWithMargins = rectWithMargins
141+
}
142+
137143
/*
138144
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
139145
view's transform (UIView.transform).

Sources/Pin.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ import Foundation
4545
self.layoutDirection = direction
4646
}
4747

48+
internal static var autoSizingInProgress: Bool = false
49+
4850
//
4951
// Warnings
5052
//

0 commit comments

Comments
 (0)