@@ -10,109 +10,115 @@ import Foundation
1010
1111// MARK: - LayoutItemFactory
1212struct 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
5965private 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
125131private 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
218238private 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