Skip to content

Commit a1f2869

Browse files
author
Luc Dion
committed
Add method that can pin multiples edges:
* `all()`: Pin all edges on its superview's corresponding edges (top, bottom, left, right). Similar to calling `view.top().bottom().left().right()` * `horizontally()`: Pin the left and right edges on its superview's corresponding edges. Similar to calling `view.left().right()`. * `vertically()`: Pin the **top and bottom edges** on its superview's corresponding edges. Similar to calling `view.top().bottom()`.
1 parent 6a24362 commit a1f2869

File tree

14 files changed

+103
-63
lines changed

14 files changed

+103
-63
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class AdjustToContainerView: BaseView {
4444
super.layoutSubviews()
4545

4646
// Layout the contentView using the view's safeArea.
47-
contentView.pin.top().bottom().left().right().margin(safeArea)
47+
contentView.pin.all().margin(safeArea)
4848

4949
languageSelectorView.pin.top().left().right().fitSize()
5050
swiftOpinionSelectorView.pin.below(of: languageSelectorView, aligned: .left).right().marginTop(10).fitSize()

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class ChoiceSelectorView: UIView {
6363
if frame.width > 500 {
6464
// The UISegmentedControl is at the top-right corner and the label takes the remaining horizontal space.
6565
segmentedControl.pin.top().right().margin(margin)
66-
textLabel.pin.top().left().left(of: segmentedControl).margin(margin).fitSize()
66+
textLabel.pin.top().left().before(of: segmentedControl).margin(margin).fitSize()
6767
} else {
6868
// The UISegmentedControl is placed below the label.
6969
textLabel.pin.top().left().right().margin(margin).fitSize()

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

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

7777
// Layout the contentScrollView using the view's safeArea.
78-
contentScrollView.pin.top().bottom().left().right().margin(safeArea)
78+
contentScrollView.pin.all().margin(safeArea)
7979

8080
row1.pin.top().left().right().height(40)
8181
row1Item1.pin.top().left().bottom().width(50).margin(2)
@@ -86,7 +86,7 @@ class AutoAdjustingSizeView: BaseView {
8686
row2Item2.pin.left(of: row2Item1, aligned: .top).left().bottom().margin(0, 2, 2, 2)
8787

8888
row3.pin.below(of: row2, aligned: .left).size(of: row1).marginTop(10)
89-
row3Item1.pin.topCenter().width(50).bottom().margin(2)
89+
row3Item1.pin.topCenter().bottom().width(50).margin(2)
9090
row3Item2.pin.left(of: row3Item1, aligned: .top).left().bottom().margin(0, 2, 2, 2)
9191
row3Item3.pin.right(of: row3Item1, aligned: .top).right().bottom().margin(0, 2, 2, 2)
9292

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ class IntroView: BaseView {
6060

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

6565
logo.pin.top().left().size(100).aspectRatio().marginTop(10)
66-
segmented.pin.right(of: logo, aligned: .top).right().marginLeft(10)
66+
segmented.pin.after(of: logo, aligned: .top).right().marginLeft(10)
6767
textLabel.pin.below(of: segmented, aligned: .left).width(of: segmented).pinEdges().marginTop(10).fitSize()
6868
separatorView.pin.below(of: [logo, textLabel], aligned: .left).right(to: segmented.edge.right).marginTop(10)
6969
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class IntroRTLView: BaseView {
6565

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

7070
logo.pin.top().start().size(100).aspectRatio().marginTop(10)
7171
segmented.pin.after(of: logo, aligned: .top).end().marginStart(10)

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ class MultiRelativeView: BaseView {
4545
super.layoutSubviews()
4646

4747
// Layout the contentView using the view's safeArea.
48-
contentView.pin.top().bottom().left().right().margin(safeArea)
48+
contentView.pin.all().margin(safeArea)
4949

5050
view1.pin.top().left().width(20%).height(50%)
5151
view2.pin.top().right().width(20%).height(50%)

Example/PinLayoutSample/UI/Examples/TableViewExample/Cells/MethodCell.swift

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class MethodCell: UITableViewCell {
2626
fileprivate let iconImageView = UIImageView(image: UIImage(named: "method"))
2727
fileprivate let nameLabel = UILabel()
2828
fileprivate let descriptionLabel = UILabel()
29-
29+
fileprivate let margin: CGFloat = 10
30+
3031
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
3132
super.init(style: style, reuseIdentifier: reuseIdentifier)
3233

@@ -50,35 +51,28 @@ class MethodCell: UITableViewCell {
5051

5152
func configure(method: Method) {
5253
nameLabel.text = method.name
53-
nameLabel.sizeToFit()
54-
5554
descriptionLabel.text = method.description
56-
descriptionLabel.sizeToFit()
5755
}
5856

5957
override func layoutSubviews() {
6058
super.layoutSubviews()
6159
layout()
6260
}
6361

64-
@discardableResult
65-
fileprivate func layout() -> CGSize {
66-
let margin: CGFloat = 10
67-
68-
// 1) Layout controls
62+
fileprivate func layout() {
6963
iconImageView.pin.top().left().size(30).margin(margin)
7064
nameLabel.pin.right(of: iconImageView, aligned: .center).right().marginHorizontal(margin).fitSize()
7165
descriptionLabel.pin.below(of: [iconImageView, nameLabel]).left().right().margin(margin).fitSize()
72-
73-
// 2) Returns a size that contains all controls
74-
return CGSize(width: contentView.frame.width, height: descriptionLabel.frame.maxY + margin)
7566
}
7667

7768
override func sizeThatFits(_ size: CGSize) -> CGSize {
7869
// 1) Set the contentView's width to the specified size parameter
7970
contentView.pin.width(size.width)
8071

8172
// 2) Layout the contentView's controls
82-
return layout()
73+
layout()
74+
75+
// 3) Returns a size that contains all controls
76+
return CGSize(width: contentView.frame.width, height: descriptionLabel.frame.maxY + margin)
8377
}
8478
}

Example/PinLayoutSample/UI/Examples/TableViewExample/Cells/MethodGroupHeader.swift

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ class MethodGroupHeader: UITableViewHeaderFooterView {
2929
super.init(reuseIdentifier: reuseIdentifier)
3030

3131
titleLabel.font = UIFont.systemFont(ofSize: 20)
32-
titleLabel.sizeToFit()
3332
contentView.addSubview(titleLabel)
3433
}
3534

@@ -39,13 +38,11 @@ class MethodGroupHeader: UITableViewHeaderFooterView {
3938

4039
func configure(title: String) {
4140
titleLabel.text = title
42-
titleLabel.sizeToFit()
4341
}
4442

4543
override func layoutSubviews() {
4644
super.layoutSubviews()
4745

48-
// Center the label vertically. Note that we don't need to specify the size, it has already be adjusted in init().
49-
titleLabel.pin.left().right().vCenter().margin(10)
46+
titleLabel.pin.left().right().vCenter().margin(10).fitSize()
5047
}
5148
}

Example/PinLayoutSample/UI/Examples/TableViewExample/TableViewExampleView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class TableViewExampleView: BaseView {
5050
override func layoutSubviews() {
5151
super.layoutSubviews()
5252

53-
tableView.pin.top().bottom().left().right()
53+
tableView.pin.all()
5454
}
5555
}
5656

README.md

Lines changed: 50 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ override func layoutSubviews() {
8282
super.layoutSubviews()
8383

8484
logo.pin.top().left().size(100).aspectRatio().margin(10)
85-
segmented.pin.right(of: logo, aligned: .top).right().marginHorizontal(10)
85+
segmented.pin.after(of: logo, aligned: .top).right().marginHorizontal(10)
8686
textLabel.pin.below(of: segmented, aligned: .left).right().marginTop(10).marginRight(10).fitSize()
8787
separatorView.pin.below(of: [logo, textLabel], aligned: .left).right(to: segmented.edge.right).marginTop(10)
8888
}
@@ -113,7 +113,7 @@ This example shows how easily PinLayout can adjust its layout based on the view'
113113
segmentedControl.pin.below(of: textLabel).right().margin(margin)
114114
} else {
115115
segmentedControl.pin.top().right().margin(margin)
116-
textLabel.pin.top().left().left(of: segmentedControl).margin(margin).fitSize()
116+
textLabel.pin.top().left().before(of: segmentedControl).margin(margin).fitSize()
117117
}
118118
```
119119

@@ -252,7 +252,7 @@ In LTR direction the value specifies the right edge distance from the superview'
252252
In RTL direction the value specifies the left edge distance from the superview's left edge in pixels.
253253
* **`end(_ percent: Percent)`**:left_right_arrow:
254254
In LTR direction the value specifies the right edge distance from the superview's right edge in percentage of its superview's width.
255-
In RTL direction the value specifies the left edge distance from the superview's left edge in percentage of its superview's width.
255+
In RTL direction the value specifies the left edge distance from the superview's left edge in percentage of its superview's width.
256256

257257
###### Usage Examples:
258258

@@ -273,7 +273,7 @@ This example layout the view A to fit its superview frame with a margin of 10 pi
273273
Another possible solution using other PinLayout's methods (more details later):
274274

275275
```swift
276-
view.pin.top().bottom().left().right().margin(10)
276+
view.pin.all().margin(10)
277277
```
278278

279279
<br/>
@@ -301,21 +301,36 @@ Position the view left edge directly on its superview left edge in LTR direction
301301
* **`end()`**:left_right_arrow:
302302
Position the view right edge directly on its superview right edge in LTR direction or left edge directly on its superview left edge in RTL direction. Similar to calling `end(0)`.
303303

304+
**Methods pinning multiple edges**:
305+
306+
* **`all()`**
307+
Pin **all edges** on its superview's corresponding edges (top, bottom, left, right).
308+
Similar to calling `view.top().bottom().left().right()`.
309+
* **`horizontally()`**
310+
Pin the **left and right edges** on its superview's corresponding edges.
311+
Similar to calling `view.left().right()`.
312+
* **`vertically()`**
313+
Pin the **top and bottom edges** on its superview's corresponding edges.
314+
Similar to calling `view.top().bottom()`.
315+
316+
304317
###### Usage examples:
305318
```swift
306319
view.pin.top().left()
307320
view.pin.bottom().right()
308321
view.pin.hCenter().vCenter()
309322
view.pin.start().end()
323+
view.pin.all()
324+
view.pin.top().horizontally()
310325
```
311326

312327
###### Example:
313-
This example is similar to the previous example, but pins edges directly on superview’s edges. It will layout the view A to fit its superview frame with a margin of 10 pixels.
328+
This example is similar to the previous example, but pins edges directly on superview’s edges. It will layout the view A to fit its superview frame with a margin of 10 pixels all around.
314329

315330
![](docs/02-example-superview-edge.png)
316331

317332
```swift
318-
viewA.pin.top().left().bottom().right().margin(10)
333+
viewA.pin.all().margin(10)
319334
```
320335

321336
<br/>
@@ -537,14 +552,6 @@ Position the view above the specified view(s). One or many relative views can be
537552
**`below(of: [UIView])`**
538553
Position the view below the specified view(s). One or many relative views can be specified. This method is similar to pinning the view’s top edge.
539554

540-
* **`left(of: UIView)`**
541-
**`left(of: [UIView])`**
542-
Position the view left of the specified view(s). One or many relative views can be specified. This method is similar to pinning the view’s right edge.
543-
544-
* **`right(of: UIView)`**
545-
**`right(of: [UIView])`**
546-
Position the view right of the specified view(s). One or many relative views can be specified. This method is similar to pinning the view’s left edge.
547-
548555
* **`before(of: UIView)`**:left_right_arrow:
549556
**`before(of: [UIView])`**:left_right_arrow:
550557
In LTR direction the view is positionned at the left of the specified view(s). In RTL direction the view is positionned at the right. One or many relative views can be specified.
@@ -553,6 +560,14 @@ In LTR direction the view is positionned at the left of the specified view(s). I
553560
**`after(of: [UIView])`**:left_right_arrow:
554561
In LTR direction the view is positionned at the right of the specified view(s). In RTL direction the view is positionned at the left. One or many relative views can be specified.
555562

563+
* **`left(of: UIView)`**
564+
**`left(of: [UIView])`**
565+
Position the view left of the specified view(s). Similar to `before(of:)`. One or many relative views can be specified. This method is similar to pinning the view’s right edge.
566+
567+
* **`right(of: UIView)`**
568+
**`right(of: [UIView])`**
569+
Position the view right of the specified view(s). Similar to `after(of:)`. One or many relative views can be specified. This method is similar to pinning the view’s left edge.
570+
556571
:pushpin: **Multiple relative views**: If for example a call to `below(of: [...]) specify multiple relative views, the view will be layouted below *ALL* these views.
557572

558573
:pushpin: These methods **set the position of a view's edge**: top, left, bottom or right. For example `below(of ...)` set the view's top edge, `right(of ...) set the view's left edge, ...
@@ -561,10 +576,10 @@ In LTR direction the view is positionned at the right of the specified view(s).
561576

562577
###### Usage examples:
563578
```swift
579+
view.pin.after(of: view4).before(of: view1).below(of: view3)
564580
view.pin.left(of: view2)
565581
view.pin.below(of: [view2, view3, view4])
566582
view.pin.left(of: view1).above(of: view2).right(of: view4).below(of: view3)
567-
view.pin.after(of: view4).before(of: view1).below(of: view3)
568583
```
569584

570585
###### Example:
@@ -573,7 +588,7 @@ The following example will position the view C between the view A and B with mar
573588
![](docs/pinlayout-relative.png)
574589

575590
```swift
576-
viewC.pin.top().left(of: viewA).right(of: viewB).margin(10)
591+
viewC.pin.top().after(of: viewA).before(of: viewB).margin(10)
577592
```
578593
This is an equivalent solution using [edges](#edge):
579594

@@ -584,7 +599,7 @@ This is an equivalent solution using [edges](#edge):
584599
This is also an equivalent solution using [relative positioning and alignment](#relative_positioning_w_alignment) explained in the next section:
585600

586601
```swift
587-
viewC.pin.left(of: viewA, aligned: .top).right(of: viewB, aligned: top).marginHorizontal(10)
602+
viewC.pin.after(of: viewA, aligned: .top).before(of: viewB, aligned: top).marginHorizontal(10)
588603
```
589604

590605

@@ -605,14 +620,6 @@ Position the view above the specified view(s) and aligned it using the specified
605620
**`below(of: [UIView], aligned: HorizontalAlignment)`**
606621
Position the view below the specified view(s) and aligned it using the specified HorizontalAlignment. One or many relative views can be specified. This method is similar to pinning one view’s anchor: topLeft, topCenter or topRight.
607622

608-
* **`left(of: UIView, aligned: VerticalAlignment)`**
609-
**`left(of: [UIView], aligned: HorizontalAlignment)`**
610-
Position the view left of the specified view(s) and aligned it using the specified VerticalAlignment. One or many relative views can be specified. This method is similar to pinning one view’s anchor: topRight, centerRight or bottomRight.
611-
612-
* **`right(of: UIView, aligned: VerticalAlignment)`**
613-
**`right(of: [UIView], aligned: HorizontalAlignment)`**
614-
Position the view right of the specified view(s) and aligned it using the specified VerticalAlignment. One or many relative views can be specified. This method is similar to pinning one view’s anchor: topLeft, centerLeft or bottomLeft.
615-
616623
* **`before(of: UIView, aligned: HorizontalAlignment)`**:left_right_arrow:
617624
**`before(of: [UIView], aligned: HorizontalAlignment)`**:left_right_arrow:
618625
In LTR direction the view is positionned at the left of the specified view(s). In RTL direction the view is positionned at the right. One or many relative views can be specified.
@@ -621,6 +628,14 @@ In LTR direction the view is positionned at the left of the specified view(s). I
621628
**`after(of: [UIView], aligned: HorizontalAlignment)`**:left_right_arrow:
622629
In LTR direction the view is positionned at the right of the specified view(s). In RTL direction the view is positionned at the left. One or many relative views can be specified.
623630

631+
* **`left(of: UIView, aligned: VerticalAlignment)`**
632+
**`left(of: [UIView], aligned: HorizontalAlignment)`**
633+
Position the view left of the specified view(s) and aligned it using the specified VerticalAlignment. Similar to `before(of:)`. One or many relative views can be specified. This method is similar to pinning one view’s anchor: topRight, centerRight or bottomRight.
634+
635+
* **`right(of: UIView, aligned: VerticalAlignment)`**
636+
**`right(of: [UIView], aligned: HorizontalAlignment)`**
637+
Position the view right of the specified view(s) and aligned it using the specified VerticalAlignment. Similar to `after(of:)`. One or many relative views can be specified. This method is similar to pinning one view’s anchor: topLeft, centerLeft or bottomLeft.
638+
624639

625640
**How alignment is applied:**
626641

@@ -648,7 +663,7 @@ In RTL direction the view's left edge will be aligned to the right most relative
648663
```swift
649664
view.pin.above(of: view2, aligned: .left)
650665
view.pin.below(of: [view2, view3, view4], aligned: .left)
651-
view.pin.left(of: view2, aligned: .top).right(of: view3, aligned: .bottom)
666+
view.pin.after(of: view2, aligned: .top).before(of: view3, aligned: .bottom)
652667
```
653668

654669
###### Example:
@@ -781,7 +796,7 @@ The following example layout the UILabel on the right side of the UIImageView wi
781796
![](docs/pinlayout-fitSize.png)
782797

783798
```javascript
784-
label.pin.right(of: image, aligned: .top).right().marginHorizontal(10).fitSize()
799+
label.pin.after(of: image, aligned: .top).right().marginHorizontal(10).fitSize()
785800
```
786801

787802

@@ -930,7 +945,7 @@ This example centered horizontally the view B in the space remaining at the righ
930945
![](docs/pinlayout-example-justify-remaining-space.png)
931946

932947
```swift
933-
viewB.pin.left(of: viewA, aligned: .top).right().width(100).justify(.center)
948+
viewB.pin.after(of: viewA, aligned: .top).right().width(100).justify(.center)
934949
```
935950

936951
<br/>
@@ -1160,7 +1175,7 @@ Warnings can be disabled also in debug mode by setting the boolean Pin.logWarnin
11601175

11611176
```swift
11621177
textLabel.pin.below(of: titleLabel)
1163-
.right(of: statusIcon).left(of: accessoryView)
1178+
.before(of: statusIcon).after(of: accessoryView)
11641179
.above(of: button).marginHorizontal(10)
11651180
```
11661181

@@ -1182,7 +1197,7 @@ Cell A:
11821197

11831198
```swift
11841199
a1.pin.top().bottom().left().width(50)
1185-
a2.pin.right(of: a1, aligned: .top).bottom().right().marginLeft(10)
1200+
a2.pin.after(of: a1, aligned: .top).bottom().right().marginLeft(10)
11861201
```
11871202

11881203
Cell B:
@@ -1192,7 +1207,7 @@ Cell B:
11921207

11931208
```swift
11941209
b2.pin.top().bottom().right().width(50)
1195-
b1.pin.left(of: b2, aligned: .top).bottom().left().marginRight(10)
1210+
b1.pin.before(of: b2, aligned: .top).bottom().left().marginRight(10)
11961211
```
11971212

11981213
Cell C:
@@ -1203,8 +1218,8 @@ Cell C:
12031218

12041219
```swift
12051220
c2.pin.topCenter().width(50).bottom()
1206-
c1.pin.left(of: c1, aligned: .top).bottom().left().marginRight(10)
1207-
c3.pin.right(of: c2, aligned: .top).bottom().right().marginLeft(10)
1221+
c1.pin.before(of: c2, aligned: .top).bottom().left().marginRight(10)
1222+
c3.pin.after(of: c2, aligned: .top).bottom().right().marginLeft(10)
12081223
```
12091224

12101225
Cell D:
@@ -1215,8 +1230,8 @@ Cell D:
12151230

12161231
```swift
12171232
d1.pin.topLeft().bottom().width(25%)
1218-
d2.pin.right(of: d1, aligned: .top).bottom().width(50%).marginLeft(10)
1219-
d3.pin.right(of: d2, aligned: .top).bottom().right().marginLeft(10)
1233+
d2.pin.after(of: d1, aligned: .top).bottom().width(50%).marginLeft(10)
1234+
d3.pin.after(of: d2, aligned: .top).bottom().right().marginLeft(10)
12201235
```
12211236

12221237
<br>

0 commit comments

Comments
 (0)