Skip to content

Commit 275115e

Browse files
authored
Merge pull request #108 from mirego/handle_parent_with_transform
PinLayout now handle correctly parents (superviews) with transforms.
2 parents e66037d + df2216b commit 275115e

File tree

6 files changed

+207
-66
lines changed

6 files changed

+207
-66
lines changed

PinLayout.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,6 @@
229229
240F88BC1F0C042500280FC8 /* JustifyAlignSpec.swift */,
230230
243B12C41FC3CFC10072A9C3 /* LayoutMethodSpec.swift */,
231231
244C6E141E776A0C0074FC74 /* MarginsSpec.swift */,
232-
245C1DA11FEC4FC6007594F7 /* TransformSpec.swift */,
233232
242723711F008B85006A5C3A /* MinMaxWidthHeightSpec.swift */,
234233
243B12C91FC469550072A9C3 /* ObjectiveCSpec.m */,
235234
249EFE881E64FB4C00165E39 /* PinLayoutTests.swift */,
@@ -240,6 +239,7 @@
240239
2469C5031E75DB7600073BEE /* RectNimbleMatcher.swift */,
241240
2482908B1E78CFFC00667D08 /* RelativePositionSpec.swift */,
242241
242E8DC11EED5982005935FB /* RelativePositionMultipleViewsSpec.swift */,
242+
245C1DA11FEC4FC6007594F7 /* TransformSpec.swift */,
243243
240F88BF1F0C1ED900280FC8 /* WarningSpec.swift */,
244244
248E4C751F7A88CF00C0E7F7 /* UIImage+Color.swift */,
245245
);

Sources/Impl/Coordinates.swift

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class Coordinates {
7676
height: ceilFloatToDisplayScale(rect.size.height))
7777
}
7878

79-
static func setViewRectUsingDisplayScale(view: UIView, toRect rect: CGRect) {
79+
static func setUntransformedViewRect(_ view: UIView, toRect rect: CGRect) {
8080
/*
8181
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
8282
view's transform (UIView.transform).
@@ -87,6 +87,19 @@ class Coordinates {
8787
view.center = CGPoint(x: adjustedRect.midX, y: adjustedRect.midY)
8888
view.bounds = CGRect(origin: .zero, size: adjustedRect.size)
8989
}
90+
91+
static func getUntransformedViewRect(_ view: UIView) -> CGRect {
92+
/*
93+
To adjust the view's position and size, we don't set the UIView's frame directly, because we want to keep the
94+
view's transform (UIView.transform).
95+
By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep
96+
the view's transform. So view's transforms won't be affected/altered by PinLayout.
97+
*/
98+
let bounds = view.bounds
99+
let origin = CGPoint(x: view.center.x - bounds.width / 2, y: view.center.y - bounds.height / 2)
100+
101+
return CGRect(origin: origin, size: bounds.size)
102+
}
90103

91104
static func roundFloatToDisplayScale(_ pointValue: CGFloat) -> CGFloat {
92105
return CGFloat(roundf(Float(pointValue * displayScale))) / displayScale

Sources/Impl/PinLayoutImpl+Coordinates.swift

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@ extension PinLayoutImpl {
5151

5252
@discardableResult
5353
internal func left(_ percent: Percent, _ context: Context) -> PinLayout {
54-
guard let layoutSuperview = layoutSuperview(context) else { return self }
55-
setLeft(percent.of(layoutSuperview.frame.width), context)
54+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
55+
setLeft(percent.of(layoutSuperviewRect.width), context)
5656
return self
5757
}
5858

@@ -78,22 +78,22 @@ extension PinLayoutImpl {
7878

7979
@discardableResult
8080
internal func right(_ context: Context) -> PinLayout {
81-
guard let layoutSuperview = layoutSuperview(context) else { return self }
82-
setRight(layoutSuperview.frame.width, context)
81+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
82+
setRight(layoutSuperviewRect.width, context)
8383
return self
8484
}
8585

8686
@discardableResult
8787
internal func right(_ value: CGFloat, _ context: Context) -> PinLayout {
88-
guard let layoutSuperview = layoutSuperview(context) else { return self }
89-
setRight(layoutSuperview.frame.width - value, context)
88+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
89+
setRight(layoutSuperviewRect.width - value, context)
9090
return self
9191
}
9292

9393
@discardableResult
9494
internal func right(_ percent: Percent, _ context: Context) -> PinLayout {
95-
guard let layoutSuperview = layoutSuperview(context) else { return self }
96-
setRight(layoutSuperview.frame.width - percent.of(layoutSuperview.frame.width), context)
95+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
96+
setRight(layoutSuperviewRect.width - percent.of(layoutSuperviewRect.width), context)
9797
return self
9898
}
9999

@@ -123,15 +123,15 @@ extension PinLayoutImpl {
123123

124124
@discardableResult
125125
internal func bottom(_ context: Context) -> PinLayout {
126-
guard let layoutSuperview = layoutSuperview(context) else { return self }
127-
setBottom(layoutSuperview.frame.height, context)
126+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
127+
setBottom(layoutSuperviewRect.height, context)
128128
return self
129129
}
130130

131131
@discardableResult
132132
internal func bottom(_ value: CGFloat, _ context: Context) -> PinLayout {
133-
guard let layoutSuperview = layoutSuperview(context) else { return self }
134-
setBottom(layoutSuperview.frame.height - value, context)
133+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
134+
setBottom(layoutSuperviewRect.height - value, context)
135135
return self
136136
}
137137

Sources/Impl/PinLayoutImpl+Layouting.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ extension PinLayoutImpl {
127127
By setting the view's center and bounds we really set the frame of the non-transformed view, and this keep
128128
the view's transform. So view's transforms won't be affected/altered by PinLayout.
129129
*/
130-
Coordinates.setViewRectUsingDisplayScale(view: view, toRect: newRect)
130+
Coordinates.setUntransformedViewRect(view, toRect: newRect)
131131
}
132132

133133
private func handlePinEdges() {

Sources/Impl/PinLayoutImpl.swift

Lines changed: 56 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ class PinLayoutImpl: PinLayout {
9292
@discardableResult
9393
func top(_ percent: Percent) -> PinLayout {
9494
func context() -> String { return "top(\(percent.description))" }
95-
guard let layoutSuperview = layoutSuperview(context) else { return self }
96-
setTop(percent.of(layoutSuperview.frame.height), context)
95+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
96+
setTop(percent.of(layoutSuperviewRect.height), context)
9797
return self
9898
}
9999

@@ -142,8 +142,8 @@ class PinLayoutImpl: PinLayout {
142142
@discardableResult
143143
func bottom(_ percent: Percent) -> PinLayout {
144144
func context() -> String { return "bottom(\(percent.description))" }
145-
guard let layoutSuperview = layoutSuperview(context) else { return self }
146-
bottom(percent.of(layoutSuperview.frame.height), context)
145+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
146+
bottom(percent.of(layoutSuperviewRect.height), context)
147147
return self
148148
}
149149

@@ -181,48 +181,48 @@ class PinLayoutImpl: PinLayout {
181181
@discardableResult
182182
func hCenter() -> PinLayout {
183183
func context() -> String { return "hCenter()" }
184-
guard let layoutSuperview = layoutSuperview(context) else { return self }
185-
setHorizontalCenter(layoutSuperview.frame.width / 2, context)
184+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
185+
setHorizontalCenter(layoutSuperviewRect.width / 2, context)
186186
return self
187187
}
188188

189189
@discardableResult
190190
func hCenter(_ value: CGFloat) -> PinLayout {
191191
func context() -> String { return "hCenter(\(value))" }
192-
guard let layoutSuperview = layoutSuperview(context) else { return self }
193-
setHorizontalCenter((layoutSuperview.frame.width / 2) + value, context)
192+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
193+
setHorizontalCenter((layoutSuperviewRect.width / 2) + value, context)
194194
return self
195195
}
196196

197197
@discardableResult
198198
func hCenter(_ percent: Percent) -> PinLayout {
199199
func context() -> String { return "hCenter(\(percent.description))" }
200-
guard let layoutSuperview = layoutSuperview(context) else { return self }
201-
setHorizontalCenter((layoutSuperview.frame.width / 2) + percent.of(layoutSuperview.frame.width), context)
200+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
201+
setHorizontalCenter((layoutSuperviewRect.width / 2) + percent.of(layoutSuperviewRect.width), context)
202202
return self
203203
}
204204

205205
@discardableResult
206206
func vCenter() -> PinLayout {
207207
func context() -> String { return "vCenter()" }
208-
guard let layoutSuperview = layoutSuperview(context) else { return self }
209-
setVerticalCenter(layoutSuperview.frame.height / 2, context)
208+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
209+
setVerticalCenter(layoutSuperviewRect.height / 2, context)
210210
return self
211211
}
212212

213213
@discardableResult
214214
func vCenter(_ value: CGFloat) -> PinLayout {
215215
func context() -> String { return "vCenter(\(value))" }
216-
guard let layoutSuperview = layoutSuperview(context) else { return self }
217-
setVerticalCenter((layoutSuperview.frame.height / 2) + value, context)
216+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
217+
setVerticalCenter((layoutSuperviewRect.height / 2) + value, context)
218218
return self
219219
}
220220

221221
@discardableResult
222222
func vCenter(_ percent: Percent) -> PinLayout {
223223
func context() -> String { return "vCenter(\(percent.description))" }
224-
guard let layoutSuperview = layoutSuperview(context) else { return self }
225-
setVerticalCenter((layoutSuperview.frame.height / 2) + percent.of(layoutSuperview.frame.height), context)
224+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
225+
setVerticalCenter((layoutSuperviewRect.height / 2) + percent.of(layoutSuperviewRect.height), context)
226226
return self
227227
}
228228

@@ -375,8 +375,8 @@ class PinLayoutImpl: PinLayout {
375375
@discardableResult
376376
func topCenter() -> PinLayout {
377377
func context() -> String { return "topCenter()" }
378-
guard let layoutSuperview = layoutSuperview(context) else { return self }
379-
setTopCenter(CGPoint(x: layoutSuperview.frame.width / 2, y: 0), context)
378+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
379+
setTopCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: 0), context)
380380
return self
381381
}
382382

@@ -395,8 +395,8 @@ class PinLayoutImpl: PinLayout {
395395
}
396396

397397
fileprivate func topRight(_ context: Context) -> PinLayout {
398-
guard let layoutSuperview = layoutSuperview(context) else { return self }
399-
setTopRight(CGPoint(x: layoutSuperview.frame.width, y: 0), context)
398+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
399+
setTopRight(CGPoint(x: layoutSuperviewRect.width, y: 0), context)
400400
return self
401401
}
402402

@@ -431,8 +431,8 @@ class PinLayoutImpl: PinLayout {
431431
}
432432

433433
fileprivate func centerLeft(_ context: Context) -> PinLayout {
434-
guard let layoutSuperview = layoutSuperview(context) else { return self }
435-
setCenterLeft(CGPoint(x: 0, y: layoutSuperview.frame.height / 2), context)
434+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
435+
setCenterLeft(CGPoint(x: 0, y: layoutSuperviewRect.height / 2), context)
436436
return self
437437
}
438438

@@ -464,8 +464,8 @@ class PinLayoutImpl: PinLayout {
464464
@discardableResult
465465
func center() -> PinLayout {
466466
func context() -> String { return "center()" }
467-
guard let layoutSuperview = layoutSuperview(context) else { return self }
468-
setCenter(CGPoint(x: layoutSuperview.frame.width / 2, y: layoutSuperview.frame.height / 2), context)
467+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
468+
setCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: layoutSuperviewRect.height / 2), context)
469469
return self
470470
}
471471

@@ -485,8 +485,8 @@ class PinLayoutImpl: PinLayout {
485485

486486
@discardableResult
487487
fileprivate func centerRight(_ context: Context) -> PinLayout {
488-
guard let layoutSuperview = layoutSuperview(context) else { return self }
489-
setCenterRight(CGPoint(x: layoutSuperview.frame.width, y: layoutSuperview.frame.height / 2), context)
488+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
489+
setCenterRight(CGPoint(x: layoutSuperviewRect.width, y: layoutSuperviewRect.height / 2), context)
490490
return self
491491
}
492492

@@ -522,8 +522,8 @@ class PinLayoutImpl: PinLayout {
522522

523523
@discardableResult
524524
fileprivate func bottomLeft(_ context: Context) -> PinLayout {
525-
guard let layoutSuperview = layoutSuperview(context) else { return self }
526-
setBottomLeft(CGPoint(x: 0, y: layoutSuperview.frame.height), context)
525+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
526+
setBottomLeft(CGPoint(x: 0, y: layoutSuperviewRect.height), context)
527527
return self
528528
}
529529

@@ -555,8 +555,8 @@ class PinLayoutImpl: PinLayout {
555555
@discardableResult
556556
func bottomCenter() -> PinLayout {
557557
func context() -> String { return "bottomCenter()" }
558-
guard let layoutSuperview = layoutSuperview(context) else { return self }
559-
setBottomCenter(CGPoint(x: layoutSuperview.frame.width / 2, y: layoutSuperview.frame.height), context)
558+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
559+
setBottomCenter(CGPoint(x: layoutSuperviewRect.width / 2, y: layoutSuperviewRect.height), context)
560560
return self
561561
}
562562

@@ -576,8 +576,8 @@ class PinLayoutImpl: PinLayout {
576576

577577
@discardableResult
578578
fileprivate func bottomRight(_ context: Context) -> PinLayout {
579-
guard let layoutSuperview = layoutSuperview(context) else { return self }
580-
setBottomRight(CGPoint(x: layoutSuperview.frame.width, y: layoutSuperview.frame.height), context)
579+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
580+
setBottomRight(CGPoint(x: layoutSuperviewRect.width, y: layoutSuperviewRect.height), context)
581581
return self
582582
}
583583

@@ -608,8 +608,8 @@ class PinLayoutImpl: PinLayout {
608608
@discardableResult
609609
func width(_ percent: Percent) -> PinLayout {
610610
func context() -> String { return "width(\(percent.description))" }
611-
guard let layoutSuperview = layoutSuperview(context) else { return self }
612-
return setWidth(percent.of(layoutSuperview.frame.width), context)
611+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
612+
return setWidth(percent.of(layoutSuperviewRect.width), context)
613613
}
614614

615615
@discardableResult
@@ -626,8 +626,8 @@ class PinLayoutImpl: PinLayout {
626626
@discardableResult
627627
func minWidth(_ percent: Percent) -> PinLayout {
628628
func context() -> String { return "minWidth(\(percent.description))" }
629-
guard let layoutSuperview = layoutSuperview(context) else { return self }
630-
return setMinWidth(percent.of(layoutSuperview.frame.width), context)
629+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
630+
return setMinWidth(percent.of(layoutSuperviewRect.width), context)
631631
}
632632

633633
@discardableResult
@@ -639,8 +639,8 @@ class PinLayoutImpl: PinLayout {
639639
@discardableResult
640640
func maxWidth(_ percent: Percent) -> PinLayout {
641641
func context() -> String { return "maxWidth(\(percent.description))" }
642-
guard let layoutSuperview = layoutSuperview(context) else { return self }
643-
return setMaxWidth(percent.of(layoutSuperview.frame.width), context)
642+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
643+
return setMaxWidth(percent.of(layoutSuperviewRect.width), context)
644644
}
645645

646646
@discardableResult
@@ -651,8 +651,8 @@ class PinLayoutImpl: PinLayout {
651651
@discardableResult
652652
func height(_ percent: Percent) -> PinLayout {
653653
func context() -> String { return "height(\(percent.description))" }
654-
guard let layoutSuperview = layoutSuperview(context) else { return self }
655-
return setHeight(percent.of(layoutSuperview.frame.height), context)
654+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
655+
return setHeight(percent.of(layoutSuperviewRect.height), context)
656656
}
657657

658658
@discardableResult
@@ -669,8 +669,8 @@ class PinLayoutImpl: PinLayout {
669669
@discardableResult
670670
func minHeight(_ percent: Percent) -> PinLayout {
671671
func context() -> String { return "minHeight(\(percent.description))" }
672-
guard let layoutSuperview = layoutSuperview(context) else { return self }
673-
return setMinHeight(percent.of(layoutSuperview.frame.height), context)
672+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
673+
return setMinHeight(percent.of(layoutSuperviewRect.height), context)
674674
}
675675

676676
@discardableResult
@@ -682,8 +682,8 @@ class PinLayoutImpl: PinLayout {
682682
@discardableResult
683683
func maxHeight(_ percent: Percent) -> PinLayout {
684684
func context() -> String { return "maxHeight(\(percent.description))" }
685-
guard let layoutSuperview = layoutSuperview(context) else { return self }
686-
return setMaxHeight(percent.of(layoutSuperview.frame.height), context)
685+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
686+
return setMaxHeight(percent.of(layoutSuperviewRect.height), context)
687687
}
688688

689689
//
@@ -702,8 +702,8 @@ class PinLayoutImpl: PinLayout {
702702
@discardableResult
703703
func size(_ percent: Percent) -> PinLayout {
704704
func context() -> String { return "size(\(percent.description))" }
705-
guard let layoutSuperview = layoutSuperview(context) else { return self }
706-
let size = CGSize(width: percent.of(layoutSuperview.frame.width), height: percent.of(layoutSuperview.frame.height))
705+
guard let layoutSuperviewRect = layoutSuperviewRect(context) else { return self }
706+
let size = CGSize(width: percent.of(layoutSuperviewRect.width), height: percent.of(layoutSuperviewRect.height))
707707
return setSize(size, context)
708708
}
709709

@@ -914,6 +914,15 @@ extension PinLayoutImpl {
914914
return self
915915
}
916916

917+
internal func layoutSuperviewRect(_ context: Context) -> CGRect? {
918+
if let superview = view.superview {
919+
return Coordinates.getUntransformedViewRect(superview)
920+
} else {
921+
warnWontBeApplied("the view must be added as a sub-view before being layouted using this method.", context)
922+
return nil
923+
}
924+
}
925+
917926
internal func layoutSuperview(_ context: Context) -> UIView? {
918927
if let superview = view.superview {
919928
return superview
@@ -923,6 +932,7 @@ extension PinLayoutImpl {
923932
}
924933
}
925934

935+
// CHECK THIS!!!
926936
internal func referenceSuperview(_ referenceView: UIView, _ context: Context) -> UIView? {
927937
if let superview = referenceView.superview {
928938
return superview

0 commit comments

Comments
 (0)