Skip to content

Commit bdc158e

Browse files
Merge pull request #20 from NSMyself/fix/layoutGuide
Fix layout guide issue
2 parents b753c05 + 7d6f261 commit bdc158e

3 files changed

Lines changed: 245 additions & 216 deletions

File tree

Constrictor.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22
s.swift_version = "4.2"
33
s.name = "Constrictor"
4-
s.version = "4.1.0"
4+
s.version = "4.1.1"
55
s.summary = "🐍 AutoLayout's µFramework"
66

77
s.description = "(Boe) Constrictor's AutoLayout µFramework with the goal of simplying your constraints by reducing the amount of code you have to write."

Constrictor/Constrictor/Factory/LayoutItemFactory.swift

Lines changed: 93 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -10,109 +10,115 @@ import Foundation
1010

1111
// MARK: - LayoutItemFactory
1212
struct LayoutItemFactory {
13-
13+
14+
// MARK: Constants
15+
private enum Constants {
16+
17+
static let fakeSafeAreaIdentifier = "fakeSafeArea"
18+
}
19+
1420
/**
1521
Converts a set of attributes, elements and constant into two LayoutItems
16-
22+
1723
- parameters:
1824
- firstElement: Optional Constrictable's to extract NSLayoutConstraint.Attribute from.
1925
- secondElement: Optional Constrictable's to extract NSLayoutConstraint.Attribute from.
2026
- firstAttribute: ConstrictorAttributor from the first element.
2127
- secondAttribute: ConstrictorAttributor from the second element.
2228
- constant: Constant to be applied to the first element.
23-
29+
2430
- returns:
2531
Tuple containing an HeadLayoutImte & TailLayoutItem (starting anchor and ending anchor).
2632
*/
2733
static func makeLayoutItems(firstElement: Constrictable?, secondElement: Constrictable?,
2834
firstAttribute: ConstrictorAttribute, secondAttribute: ConstrictorAttribute,
2935
constant: Constant) -> (head: HeadLayoutItem, tail: TailLayoutItem) {
30-
36+
3137
let firstItem = layoutItem(for: firstElement, attribute: firstAttribute, constant: constant)
3238
let secondItem = layoutItem(for: secondElement, attribute: secondAttribute, constant: constant)
33-
39+
3440
return (firstItem.asHead, secondItem.asTail)
3541
}
36-
42+
3743
/**
3844
Converts an attribute, element and constant into a LayoutItem
39-
45+
4046
- parameters:
4147
- element: Optional Constrictable's to extract NSLayoutConstraint.Attribute from.
4248
- attribute: ConstrictorAttributor from the element.
4349
- constant: Constant to be applied.
44-
50+
4551
- returns:
4652
HeadLayoutItem
4753
*/
48-
54+
4955
static func makeLayoutItem(element: Constrictable?,
5056
attribute: ConstrictorAttribute,
5157
constant: Constant) -> HeadLayoutItem {
52-
58+
5359
return layoutItem(for: element, attribute: attribute, constant: constant).asHead
5460
}
5561
}
5662

5763

5864
// MARK: - Decision Maker
5965
private extension LayoutItemFactory {
60-
61-
66+
67+
6268
static func layoutItem(for element: Constrictable?,
6369
attribute: ConstrictorAttribute,
6470
constant: Constant) -> LayoutItem {
65-
71+
6672
var item = LayoutItem()
67-
73+
6874
if let view = element as? UIView {
6975
item = layoutItem(view: view, with: attribute, and: constant)
7076
} else if let viewController = element as? UIViewController {
7177
item = layoutItem(viewController: viewController, with: attribute, and: constant)
7278
} else if let layoutGuide = element as? UILayoutGuide {
7379
item = layoutItem(layoutGuide: layoutGuide, with: attribute, and: constant)
7480
}
75-
81+
7682
return item
7783
}
78-
84+
7985
static func layoutItem(layoutGuide: UILayoutGuide,
8086
with attribute: ConstrictorAttribute,
8187
and constantStruct: Constant) -> LayoutItem {
82-
88+
8389
return buildLayoutItem(for: attribute, with: constantStruct, safeArea: layoutGuide)
8490
}
85-
91+
8692
static func layoutItem(view: UIView,
8793
with attribute: ConstrictorAttribute,
8894
and constantStruct: Constant) -> LayoutItem {
89-
95+
9096
let safeArea: Any
91-
97+
9298
if #available(iOS 11.0, *), ConstrictorAttribute.guidedAttributes.contains(attribute) {
9399
safeArea = view.safeAreaLayoutGuide
94100
} else {
95101
safeArea = view
96102
}
97-
103+
98104
return buildLayoutItem(for: attribute, with: constantStruct, safeArea: safeArea)
99105
}
100-
106+
101107
static func layoutItem(viewController: UIViewController,
102108
with constrictorAttribute: ConstrictorAttribute,
103109
and constantStruct: Constant) -> LayoutItem {
104-
110+
105111
let safeArea: Any
106112
let atLeastiOS11: Bool
107-
113+
108114
if #available(iOS 11.0, *), ConstrictorAttribute.guidedAttributes.contains(constrictorAttribute) {
109115
safeArea = viewController.view.safeAreaLayoutGuide
110116
atLeastiOS11 = true
111117
} else {
112118
safeArea = viewController.view
113119
atLeastiOS11 = false
114120
}
115-
121+
116122
return buildLayoutItem(for: constrictorAttribute,
117123
with: constantStruct,
118124
viewController: viewController,
@@ -123,115 +129,136 @@ private extension LayoutItemFactory {
123129

124130
// MARK: - Builder
125131
private extension LayoutItemFactory {
126-
132+
127133
static func buildLayoutItem(for constrictorAttribute: ConstrictorAttribute,
128134
with constantStruct: Constant,
129135
viewController: UIViewController? = nil,
130136
atLeastiOS11: Bool? = nil,
131137
safeArea: Any) -> LayoutItem {
132-
138+
133139
let attribute: NSLayoutConstraint.Attribute
134140
let constant: CGFloat
135141
var element = safeArea
136-
142+
137143
switch constrictorAttribute {
138144
case .top:
139145
attribute = .top
140146
constant = constantStruct.top
141-
147+
142148
case .topGuide:
143149
attribute = .top
144150
constant = constantStruct.top
145-
146-
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11, let vc = viewController { element = vc.topLayoutGuide
151+
152+
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11,
153+
let vc = viewController, let fakeSafeArea = safeLayoutGuide(for: vc) {
154+
155+
element = fakeSafeArea
156+
147157
} else { element = safeArea }
148-
158+
149159
case .bottom:
150160
attribute = .bottom
151161
constant = -constantStruct.bottom
152-
162+
153163
case .bottomGuide:
154164
attribute = .bottom
155165
constant = -constantStruct.bottom
156-
157-
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11, let vc = viewController { element = vc.bottomLayoutGuide
166+
167+
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11,
168+
let vc = viewController, let fakeSafeArea = safeLayoutGuide(for: vc) {
169+
170+
element = fakeSafeArea
171+
158172
} else { element = safeArea }
159-
173+
160174
case .right, .rightGuide:
161175
attribute = .right
162176
constant = -constantStruct.right
163-
177+
164178
case .left, .leftGuide:
165179
attribute = .left
166180
constant = constantStruct.left
167-
181+
168182
case .leading, .leadingGuide:
169183
attribute = .leading
170184
constant = constantStruct.leading
171-
185+
172186
case .trailing, .trailingGuide:
173187
attribute = .trailing
174188
constant = -constantStruct.trailing
175-
189+
176190
case .centerX:
177191
attribute = .centerX
178192
constant = constantStruct.x
179-
193+
180194
case .centerXGuide:
181195
attribute = .centerX
182196
constant = constantStruct.x
183-
184-
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11, let vc = viewController {
185-
element = safeLayoutGuide(for: vc)
197+
198+
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11,
199+
let vc = viewController, let fakeSafeArea = safeLayoutGuide(for: vc) {
200+
201+
element = fakeSafeArea
202+
186203
} else { element = safeArea }
187-
204+
188205
case .centerY:
189206
attribute = .centerY
190207
constant = constantStruct.y
191-
208+
192209
case .centerYGuide:
193210
attribute = .centerY
194211
constant = constantStruct.y
195-
196-
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11, let vc = viewController {
197-
element = safeLayoutGuide(for: vc)
212+
213+
if let atLeastiOS11 = atLeastiOS11, !atLeastiOS11,
214+
let vc = viewController, let fakeSafeArea = safeLayoutGuide(for: vc) {
215+
216+
element = fakeSafeArea
217+
198218
} else { element = safeArea }
199-
219+
200220
case .width:
201221
attribute = .width
202222
constant = constantStruct.width
203-
223+
204224
case .height:
205225
attribute = .height
206226
constant = constantStruct.height
207-
227+
208228
case .none:
209229
attribute = .notAnAttribute
210230
constant = 0.0
211231
}
212-
232+
213233
return LayoutItem(element: element, attribute: attribute, constant: constant)
214234
}
215235
}
216236

217237
// MARK: - Utils
218238
private extension LayoutItemFactory {
219-
239+
220240
/**
221-
Get an UILayoutGuide pinned to the viewController's safe edges.
222-
241+
Get an UILayoutGuide pinned to the viewController's safe edges.
242+
223243
- parameters:
224244
- viewController: UIViewController to get an UILayoutGuide pinned its edges
225-
245+
226246
- returns:
227247
Safe UILayoutGuide.
228248
*/
229-
230-
static func safeLayoutGuide(for viewController: UIViewController) -> UILayoutGuide {
231-
249+
250+
static func safeLayoutGuide(for viewController: UIViewController) -> UILayoutGuide? {
251+
252+
let fakeSafeArea = viewController.view.layoutGuides
253+
.filter(isFakeSafeArea)
254+
.first
255+
256+
guard fakeSafeArea == nil else { return fakeSafeArea }
257+
232258
let layoutGuide = UILayoutGuide()
259+
layoutGuide.identifier = Constants.fakeSafeAreaIdentifier
233260
viewController.view.addLayoutGuide(layoutGuide)
234-
261+
235262
NSLayoutConstraint.activate(
236263
[
237264
NSLayoutConstraint(
@@ -256,7 +283,11 @@ private extension LayoutItemFactory {
256283
)
257284
]
258285
)
259-
286+
260287
return layoutGuide
261288
}
289+
290+
static func isFakeSafeArea(_ layoutGuide: UILayoutGuide) -> Bool {
291+
return layoutGuide.identifier == Constants.fakeSafeAreaIdentifier
292+
}
262293
}

0 commit comments

Comments
 (0)