Skip to content

Commit 6013e94

Browse files
author
Luc Dion
committed
Update
1 parent f68d875 commit 6013e94

File tree

13 files changed

+74
-125
lines changed

13 files changed

+74
-125
lines changed

Example/PinLayoutSample/UI/Common/BaseFormView.swift

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,12 @@ class BaseFormView: BaseView {
4646
override func layoutSubviews() {
4747
super.layoutSubviews()
4848

49-
formScrollView.pin.top().left().bottom().right().margin(containerInsets())
49+
formScrollView.pin.top().left().bottom().right().margin(safeArea)
5050
}
5151

52-
override func didChangeLayoutGuides() {
53-
super.didChangeLayoutGuides()
54-
formScrollView.contentOffset = CGPoint(x: 0, y: topLayoutGuide)
52+
override func safeAreaDidChange() {
53+
super.safeAreaDidChange()
54+
formScrollView.contentOffset = CGPoint(x: 0, y: safeArea.top)
5555
}
5656

5757
@objc
@@ -80,12 +80,4 @@ class BaseFormView: BaseView {
8080
formScrollView.contentInset = UIEdgeInsets(top: formScrollView.contentInset.top, left: 0,
8181
bottom: bottomInset, right: 0)
8282
}
83-
84-
fileprivate func containerInsets() -> UIEdgeInsets {
85-
if #available(iOS 11.0, *) {
86-
return safeAreaInsets
87-
} else {
88-
return UIEdgeInsets.zero
89-
}
90-
}
9183
}

Example/PinLayoutSample/UI/Common/BaseView.swift

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,18 @@
2020
import UIKit
2121

2222
class BaseView: UIView {
23-
fileprivate (set) var topLayoutGuide: CGFloat = 0
24-
fileprivate (set) var bottomLayoutGuide: CGFloat = 0
23+
private var legacySafeArea: UIEdgeInsets = .zero
24+
25+
// safeArea returns UIView.safeAreaInsets for iOS 11+ or
26+
// an UIEdgeInsets initialized with the UIViewController's topLayoutGuide and
27+
// bottomLayoutGuide for other iOS versions.
28+
var safeArea: UIEdgeInsets {
29+
if #available(iOS 11.0, *) {
30+
return safeAreaInsets
31+
} else {
32+
return legacySafeArea
33+
}
34+
}
2535

2636
init() {
2737
super.init(frame: .zero)
@@ -32,25 +42,17 @@ class BaseView: UIView {
3242
fatalError("init(coder:) has not been implemented")
3343
}
3444

35-
func setLayoutGuides(top: CGFloat, bottom: CGFloat) {
36-
var didChange = false
37-
38-
if top != topLayoutGuide {
39-
topLayoutGuide = top
40-
didChange = true
41-
}
42-
43-
if bottom != bottomLayoutGuide {
44-
bottomLayoutGuide = bottom
45-
didChange = true
46-
}
47-
48-
if didChange {
49-
didChangeLayoutGuides()
50-
}
45+
func setSafeArea(_ safeArea: UIEdgeInsets) {
46+
guard safeArea != self.safeArea else { return }
47+
legacySafeArea = safeArea
48+
safeAreaDidChange()
5149
}
5250

53-
func didChangeLayoutGuides() {
51+
func safeAreaDidChange() {
5452
setNeedsLayout()
5553
}
54+
55+
override func safeAreaInsetsDidChange() {
56+
safeAreaDidChange()
57+
}
5658
}

Example/PinLayoutSample/UI/Common/BaseViewController.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@
2020
import UIKit
2121

2222
class BaseViewController: UIViewController {
23-
2423
override func viewWillLayoutSubviews() {
2524
super.viewWillLayoutSubviews()
2625

27-
if let view = view as? BaseView {
28-
view.setLayoutGuides(top: topLayoutGuide.length, bottom: bottomLayoutGuide.length)
26+
if #available(iOS 11.0, *) {
27+
} else if let view = view as? BaseView {
28+
view.setSafeArea(UIEdgeInsets(top: topLayoutGuide.length, left: 0, bottom: bottomLayoutGuide.length, right: 0))
2929
}
3030
}
3131
}

Example/PinLayoutSample/UI/Examples/AdjustToContainer/AdjustToContainerView.swift

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@ import UIKit
2121
import PinLayout
2222

2323
class AdjustToContainerView: BaseView {
24-
fileprivate let container = UIView()
24+
fileprivate let contentView = UIView()
2525
fileprivate let languageSelectorView = ChoiceSelectorView(text: "What is your favorite language?", choices: ["Swift", "Objective-C", "C++"])
2626
fileprivate let swiftOpinionSelectorView = ChoiceSelectorView(text: "Overall, are you satisfied with the Swift performance in your projects?", choices: ["Yes", "No"])
2727
fileprivate let swiftUsageSelectorView = ChoiceSelectorView(text: "How often do you typically use Swift?", choices: ["Daily", "Weekly", "Montly", "Do not use"])
2828

2929
override init() {
3030
super.init()
3131

32-
addSubview(container)
32+
addSubview(contentView)
3333

34-
container.addSubview(languageSelectorView)
35-
container.addSubview(swiftOpinionSelectorView)
36-
container.addSubview(swiftUsageSelectorView)
34+
contentView.addSubview(languageSelectorView)
35+
contentView.addSubview(swiftOpinionSelectorView)
36+
contentView.addSubview(swiftUsageSelectorView)
3737
}
3838

3939
required init?(coder aDecoder: NSCoder) {
@@ -43,18 +43,11 @@ class AdjustToContainerView: BaseView {
4343
override func layoutSubviews() {
4444
super.layoutSubviews()
4545

46-
container.pin.top().bottom().left().right().margin(containerInsets())
46+
// Layout the contentView using the view's safeArea.
47+
contentView.pin.top().bottom().left().right().margin(safeArea)
4748

4849
languageSelectorView.pin.top().left().right().fitSize()
4950
swiftOpinionSelectorView.pin.below(of: languageSelectorView, aligned: .left).right().marginTop(10).fitSize()
5051
swiftUsageSelectorView.pin.below(of: swiftOpinionSelectorView, aligned: .left).right().marginTop(10).fitSize()
5152
}
52-
53-
fileprivate func containerInsets() -> UIEdgeInsets {
54-
if #available(iOS 11.0, *) {
55-
return safeAreaInsets
56-
} else {
57-
return UIEdgeInsets(top: topLayoutGuide, left: 0, bottom: 0, right: 0)
58-
}
59-
}
6053
}

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,18 @@ class ChoiceSelectorView: UIView {
4646

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

5252
override func sizeThatFits(_ size: CGSize) -> CGSize {
53-
return layout(size: size)
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()
5458
}
5559

56-
fileprivate func layout(size: CGSize) -> CGSize {
57-
let width = size.width
60+
fileprivate func layout() -> CGSize {
5861
let margin: CGFloat = 12
5962

6063
if frame.width > 500 {
@@ -67,6 +70,6 @@ class ChoiceSelectorView: UIView {
6770
segmentedControl.pin.below(of: textLabel).right().margin(margin)
6871
}
6972

70-
return CGSize(width: width, height: max(textLabel.frame.maxY, segmentedControl.frame.maxY) + margin)
73+
return CGSize(width: frame.width, height: max(textLabel.frame.maxY, segmentedControl.frame.maxY) + margin)
7174
}
7275
}

Example/PinLayoutSample/UI/Examples/AutoAdjustingSizeView/AutoAdjustingSizeView.swift

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ class AutoAdjustingSizeView: BaseView {
7474
override func layoutSubviews() {
7575
super.layoutSubviews()
7676

77-
contentScrollView.pin.top().bottom().left().right().margin(containerInsets())
77+
// Layout the contentScrollView using the view's safeArea.
78+
contentScrollView.pin.top().bottom().left().right().margin(safeArea)
7879

7980
row1.pin.top().left().right().height(40)
8081
row1Item1.pin.top().left().bottom().width(50).margin(2)
@@ -96,12 +97,4 @@ class AutoAdjustingSizeView: BaseView {
9697

9798
contentScrollView.contentSize = CGSize(width: contentScrollView.frame.width, height: row4.frame.maxY)
9899
}
99-
100-
fileprivate func containerInsets() -> UIEdgeInsets {
101-
if #available(iOS 11.0, *) {
102-
return safeAreaInsets
103-
} else {
104-
return UIEdgeInsets.zero
105-
}
106-
}
107100
}

Example/PinLayoutSample/UI/Examples/Form/FormView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class FormView: BaseFormView {
8282
fileprivate func layoutFormFields() {
8383
let margin: CGFloat = 12
8484

85+
// Layout the formContainerView using the view's safeArea.
8586
formContainerView.pin.top().hCenter().width(100%).maxWidth(400).pinEdges().margin(margin, margin, margin)
8687

8788
formTitleLabel.pin.topCenter().margin(margin)

Example/PinLayoutSample/UI/Examples/Intro/IntroView.swift

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import PinLayout
2222

2323
class IntroView: BaseView {
2424

25-
fileprivate let container = UIView()
25+
fileprivate let contentView = UIView()
2626
fileprivate let logo = UIImageView(image: UIImage(named: "PinLayout-logo"))
2727
fileprivate let segmented = UISegmentedControl(items: ["Intro", "1", "2"])
2828
fileprivate let textLabel = UILabel()
@@ -31,24 +31,24 @@ class IntroView: BaseView {
3131
override init() {
3232
super.init()
3333

34-
addSubview(container)
34+
addSubview(contentView)
3535

3636
logo.contentMode = .scaleAspectFit
37-
container.addSubview(logo)
37+
contentView.addSubview(logo)
3838

3939
segmented.selectedSegmentIndex = 0
4040
segmented.tintColor = .pinLayoutColor
41-
container.addSubview(segmented)
41+
contentView.addSubview(segmented)
4242

4343
textLabel.text = "Swift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable.\n\nSwift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable."
4444
textLabel.font = .systemFont(ofSize: 14)
4545
textLabel.numberOfLines = 0
4646
textLabel.lineBreakMode = .byWordWrapping
47-
container.addSubview(textLabel)
47+
contentView.addSubview(textLabel)
4848

4949
separatorView.pin.height(1)
5050
separatorView.backgroundColor = .pinLayoutColor
51-
container.addSubview(separatorView)
51+
contentView.addSubview(separatorView)
5252
}
5353

5454
required init?(coder aDecoder: NSCoder) {
@@ -58,20 +58,13 @@ class IntroView: BaseView {
5858
override func layoutSubviews() {
5959
super.layoutSubviews()
6060

61-
container.pin.top().bottom().left().right().margin(containerInsets())
61+
// Layout the contentView using the view's safeArea with at least of 10 pixels all around.
62+
let containerInsets = safeArea.minInsets(UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10))
63+
contentView.pin.top().bottom().start().end().margin(containerInsets)
6264

6365
logo.pin.top().left().size(100).aspectRatio().marginTop(10)
6466
segmented.pin.right(of: logo, aligned: .top).right().marginLeft(10)
6567
textLabel.pin.below(of: segmented, aligned: .left).width(of: segmented).pinEdges().marginTop(10).fitSize()
6668
separatorView.pin.below(of: [logo, textLabel], aligned: .left).right(to: segmented.edge.right).marginTop(10)
6769
}
68-
69-
fileprivate func containerInsets() -> UIEdgeInsets {
70-
if #available(iOS 11.0, *) {
71-
// The container margin must be at least of 10 pixels all around
72-
return safeAreaInsets.minInsets(UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10))
73-
} else {
74-
return UIEdgeInsets(top: topLayoutGuide, left: 10, bottom: 0, right: 10)
75-
}
76-
}
7770
}

Example/PinLayoutSample/UI/Examples/IntroRTL/IntroRTLView.swift

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import PinLayout
2222

2323
class IntroRTLView: BaseView {
2424

25-
fileprivate let container = UIView()
25+
fileprivate let contentView = UIView()
2626
fileprivate let logo = UIImageView(image: UIImage(named: "PinLayout-logo"))
2727
fileprivate let segmented = UISegmentedControl(items: ["Intro", "1", "2"])
2828
fileprivate let textLabel = UILabel()
@@ -36,24 +36,24 @@ class IntroRTLView: BaseView {
3636
// `UIApplication.shared.userInterfaceLayoutDirection` (< iOS 9)
3737
Pin.layoutDirection(.auto)
3838

39-
addSubview(container)
39+
addSubview(contentView)
4040

4141
logo.contentMode = .scaleAspectFit
42-
container.addSubview(logo)
42+
contentView.addSubview(logo)
4343

4444
segmented.selectedSegmentIndex = 0
4545
segmented.tintColor = .pinLayoutColor
46-
container.addSubview(segmented)
46+
contentView.addSubview(segmented)
4747

4848
textLabel.text = "Swift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable.\n\nSwift manual views layouting without auto layout, no magic, pure code, full control. Concise syntax, readable & chainable."
4949
textLabel.font = .systemFont(ofSize: 14)
5050
textLabel.numberOfLines = 0
5151
textLabel.lineBreakMode = .byWordWrapping
52-
container.addSubview(textLabel)
52+
contentView.addSubview(textLabel)
5353

5454
separatorView.pin.height(1)
5555
separatorView.backgroundColor = .pinLayoutColor
56-
container.addSubview(separatorView)
56+
contentView.addSubview(separatorView)
5757
}
5858

5959
required init?(coder aDecoder: NSCoder) {
@@ -63,20 +63,13 @@ class IntroRTLView: BaseView {
6363
override func layoutSubviews() {
6464
super.layoutSubviews()
6565

66-
container.pin.top().bottom().start().end().margin(containerInsets())
66+
// Layout the contentView using the view's safeArea with at least of 10 pixels all around.
67+
let containerInsets = safeArea.minInsets(UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10))
68+
contentView.pin.top().bottom().start().end().margin(containerInsets)
6769

6870
logo.pin.top().start().size(100).aspectRatio().marginTop(10)
6971
segmented.pin.after(of: logo, aligned: .top).end().marginStart(10)
7072
textLabel.pin.below(of: segmented, aligned: .start).width(of: segmented).pinEdges().marginTop(10).fitSize()
7173
separatorView.pin.below(of: [logo, textLabel], aligned: .start).end(to: segmented.edge.end).marginTop(10)
7274
}
73-
74-
fileprivate func containerInsets() -> UIEdgeInsets {
75-
if #available(iOS 11.0, *) {
76-
// The container margin must be at least of 10 pixels all around
77-
return safeAreaInsets.minInsets(UIEdgeInsets(top: 10, left: 10, bottom: 0, right: 10))
78-
} else {
79-
return UIEdgeInsets(top: topLayoutGuide, left: 10, bottom: 0, right: 10)
80-
}
81-
}
8275
}

Example/PinLayoutSample/UI/Examples/MultiRelativeView/MultiRelativeView.swift

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import UIKit
2121
import PinLayout
2222

2323
class MultiRelativeView: BaseView {
24-
fileprivate let container = UIView()
24+
fileprivate let contentView = UIView()
2525
fileprivate let view1 = BasicView(text: "Relative view 1 (width: 20%, height: 50%)", color: .lightGray)
2626
fileprivate let view2 = BasicView(text: "Relative view 2 (width: 20%, height: 50%)", color: .lightGray)
2727
fileprivate let view = BasicView(text: "View layouted using two relative views: \n - right(of: view1, aligned: .top)\n - left(of: view2, aligned: .bottom)",
@@ -30,11 +30,11 @@ class MultiRelativeView: BaseView {
3030
override init() {
3131
super.init()
3232

33-
addSubview(container)
33+
addSubview(contentView)
3434

35-
container.addSubview(view1)
36-
container.addSubview(view2)
37-
container.addSubview(view)
35+
contentView.addSubview(view1)
36+
contentView.addSubview(view2)
37+
contentView.addSubview(view)
3838
}
3939

4040
required init?(coder aDecoder: NSCoder) {
@@ -44,19 +44,12 @@ class MultiRelativeView: BaseView {
4444
override func layoutSubviews() {
4545
super.layoutSubviews()
4646

47-
container.pin.top().bottom().left().right().margin(containerInsets())
47+
// Layout the contentView using the view's safeArea.
48+
contentView.pin.top().bottom().left().right().margin(safeArea)
4849

4950
view1.pin.top().left().width(20%).height(50%)
5051
view2.pin.top().right().width(20%).height(50%)
5152

5253
view.pin.right(of: view1, aligned: .top).left(of: view2, aligned: .bottom).marginHorizontal(10)
5354
}
54-
55-
fileprivate func containerInsets() -> UIEdgeInsets {
56-
if #available(iOS 11.0, *) {
57-
return safeAreaInsets
58-
} else {
59-
return UIEdgeInsets(top: topLayoutGuide, left: 0, bottom: 0, right: 0)
60-
}
61-
}
6255
}

0 commit comments

Comments
 (0)