Skip to content

Commit d85f389

Browse files
committed
Improve organization and comment all the things!
1 parent 72a1e14 commit d85f389

16 files changed

Lines changed: 590 additions & 140 deletions

LICENSE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2016 SwiftKick Mobile LLC
1+
Copyright (c) 2018 SwiftKick Mobile LLC
22

33

44
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

SwiftLayout.xcodeproj/project.pbxproj

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222
22AEE39F21A106DB00295C85 /* RelationalConstraintBuilder+Edges.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AEE39521A106DB00295C85 /* RelationalConstraintBuilder+Edges.swift */; };
2323
22AEE3A021A106DB00295C85 /* SelfConstraintBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 22AEE39621A106DB00295C85 /* SelfConstraintBuilder.swift */; };
2424
22AEE3A221A1078200295C85 /* SwiftLayout.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 22AEE3A121A1078200295C85 /* SwiftLayout.podspec */; };
25+
61374AEF21ADF45700E543BC /* RelationalConstraintBuilder+Custom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61374AEE21ADF45700E543BC /* RelationalConstraintBuilder+Custom.swift */; };
26+
61374AF121ADF4AA00E543BC /* Constrainable+Builders.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61374AF021ADF4AA00E543BC /* Constrainable+Builders.swift */; };
27+
61374AF321ADF4CA00E543BC /* AnchorInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61374AF221ADF4CA00E543BC /* AnchorInfo.swift */; };
28+
61374AF521ADF4EA00E543BC /* Constrainable+Anchors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61374AF421ADF4EA00E543BC /* Constrainable+Anchors.swift */; };
29+
61374AF721ADF52500E543BC /* CGFloat+SystemSpacing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 61374AF621ADF52500E543BC /* CGFloat+SystemSpacing.swift */; };
2530
/* End PBXBuildFile section */
2631

2732
/* Begin PBXFileReference section */
@@ -42,6 +47,11 @@
4247
22AEE39521A106DB00295C85 /* RelationalConstraintBuilder+Edges.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "RelationalConstraintBuilder+Edges.swift"; sourceTree = "<group>"; };
4348
22AEE39621A106DB00295C85 /* SelfConstraintBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelfConstraintBuilder.swift; sourceTree = "<group>"; };
4449
22AEE3A121A1078200295C85 /* SwiftLayout.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = SwiftLayout.podspec; sourceTree = "<group>"; };
50+
61374AEE21ADF45700E543BC /* RelationalConstraintBuilder+Custom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RelationalConstraintBuilder+Custom.swift"; sourceTree = "<group>"; };
51+
61374AF021ADF4AA00E543BC /* Constrainable+Builders.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constrainable+Builders.swift"; sourceTree = "<group>"; };
52+
61374AF221ADF4CA00E543BC /* AnchorInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnchorInfo.swift; sourceTree = "<group>"; };
53+
61374AF421ADF4EA00E543BC /* Constrainable+Anchors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Constrainable+Anchors.swift"; sourceTree = "<group>"; };
54+
61374AF621ADF52500E543BC /* CGFloat+SystemSpacing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGFloat+SystemSpacing.swift"; sourceTree = "<group>"; };
4555
/* End PBXFileReference section */
4656

4757
/* Begin PBXFrameworksBuildPhase section */
@@ -79,15 +89,20 @@
7989
isa = PBXGroup;
8090
children = (
8191
22AEE39421A106DB00295C85 /* Constrainable.swift */,
92+
61374AF021ADF4AA00E543BC /* Constrainable+Builders.swift */,
93+
61374AF421ADF4EA00E543BC /* Constrainable+Anchors.swift */,
94+
61374AF221ADF4CA00E543BC /* AnchorInfo.swift */,
8295
22AEE38D21A106DB00295C85 /* ConstraintBuilder.swift */,
8396
22AEE39021A106DB00295C85 /* DistributiveConstraintBuilder.swift */,
8497
22AEE39121A106DB00295C85 /* DistributiveConstraintBuilder+Edges.swift */,
8598
22AEE39221A106DB00295C85 /* RelationalConstraintBuilder.swift */,
8699
22AEE39321A106DB00295C85 /* RelationalConstraintBuilder+Dimensions.swift */,
87100
22AEE39521A106DB00295C85 /* RelationalConstraintBuilder+Edges.swift */,
88101
22AEE38E21A106DB00295C85 /* RelationalConstraintBuilder+Spacing.swift */,
102+
61374AEE21ADF45700E543BC /* RelationalConstraintBuilder+Custom.swift */,
89103
22AEE39621A106DB00295C85 /* SelfConstraintBuilder.swift */,
90104
22AEE38F21A106DB00295C85 /* SelfConstraintBuilder+Dimensions.swift */,
105+
61374AF621ADF52500E543BC /* CGFloat+SystemSpacing.swift */,
91106
22AEE38521A1056800295C85 /* SwiftLayout.h */,
92107
22AEE38621A1056800295C85 /* Info.plist */,
93108
);
@@ -177,12 +192,17 @@
177192
isa = PBXSourcesBuildPhase;
178193
buildActionMask = 2147483647;
179194
files = (
195+
61374AEF21ADF45700E543BC /* RelationalConstraintBuilder+Custom.swift in Sources */,
196+
61374AF121ADF4AA00E543BC /* Constrainable+Builders.swift in Sources */,
180197
22AEE39A21A106DB00295C85 /* DistributiveConstraintBuilder.swift in Sources */,
198+
61374AF521ADF4EA00E543BC /* Constrainable+Anchors.swift in Sources */,
199+
61374AF721ADF52500E543BC /* CGFloat+SystemSpacing.swift in Sources */,
181200
22AEE39721A106DB00295C85 /* ConstraintBuilder.swift in Sources */,
182201
22AEE39D21A106DB00295C85 /* RelationalConstraintBuilder+Dimensions.swift in Sources */,
183202
22AEE39E21A106DB00295C85 /* Constrainable.swift in Sources */,
184203
22AEE3A021A106DB00295C85 /* SelfConstraintBuilder.swift in Sources */,
185204
22AEE39821A106DB00295C85 /* RelationalConstraintBuilder+Spacing.swift in Sources */,
205+
61374AF321ADF4CA00E543BC /* AnchorInfo.swift in Sources */,
186206
22AEE39F21A106DB00295C85 /* RelationalConstraintBuilder+Edges.swift in Sources */,
187207
22AEE39C21A106DB00295C85 /* RelationalConstraintBuilder.swift in Sources */,
188208
22AEE39921A106DB00295C85 /* SelfConstraintBuilder+Dimensions.swift in Sources */,

SwiftLayout/AnchorInfo.swift

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//
2+
// AnchorInfo.swift
3+
// SwiftLayout
4+
//
5+
// Created by Jake Sawyer on 11/27/18.
6+
// Copyright © 2018 it.swiftkick. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
//MARK: - AnchorInfo
12+
13+
/**
14+
Internal helper struct for supplying all required attributes for creating a constraint in one simple package.
15+
As a bonus, you can look up an `AnchorInfo<T>` via `Constraiable.anchorInfo(xAxis/yAxis/dimension:)`
16+
*/
17+
struct AnchorInfo<AnchorType: AnyObject> {
18+
var item: Constrainable
19+
var attribute: NSLayoutConstraint.Attribute
20+
var anchor: NSLayoutAnchor<AnchorType>
21+
}
22+
23+
// MARK: - Anchor Types
24+
25+
/**
26+
Helper for writing custom constraints between two different `NSLayoutXAxisAnchor` anchors.
27+
28+
```
29+
// Constrain view's centerX anchor to another view's leading anchor
30+
view.constrain(to: otherView).xAxis(.centerX, to: .leading)
31+
32+
// Modify the optional arguments to specify a more advanced constraint
33+
view.constrain(to: otherView).xAxis(.centerX, to: .leading, relation: .lessThanOrEqual, constant: 0, multiplier: 0.5, activate: false)
34+
35+
// Use the constraint builder returned after each newly created constraint to access the constraints created in order
36+
let constraint = view.constrain(to: otherView).xAxis(.centerX, to: .leading, constant: 0, priority: .defaultHigh, activate: false).constraints.last!
37+
constraint.isActive = true // activate the constraint later
38+
```
39+
*/
40+
public enum XAxisAnchor {
41+
case leading, trailing, centerX
42+
}
43+
44+
/**
45+
Helper for writing custom constraints between two different `NSLayoutYAxisAnchor` anchors.
46+
47+
```
48+
// Constrain view's centerY anchor to another view's bottom anchor
49+
view.constrain(to: otherView).yAxis(.centerY, to: .bottom)
50+
51+
// Modify the optional arguments to specify a more advanced constraint
52+
view.constrain(to: otherView).yAxis(.centerY, to: .bottom, relation: .lessThanOrEqual, constant: 0, multiplier: 0.5, activate: false)
53+
54+
// Use the constraint builder returned after each newly created constraint to access the constraints created in order
55+
let constraint = view.constrain(to: otherView).yAxis(.centerY, to: .bottom, constant: 0, priority: .defaultHigh, activate: false).constraints.last!
56+
constraint.isActive = true // activate the constraint later
57+
```
58+
*/
59+
public enum YAxisAnchor {
60+
case top, bottom, centerY
61+
}
62+
63+
/**
64+
Helper for writing custom constraints between two different `NSLayoutDimension` anchors.
65+
66+
```
67+
// Constrain view's width anchor to another view's height anchor
68+
view.constrain(to: otherView).dimension(.width, to: .height)
69+
70+
// Modify the optional arguments to specify a more advanced constraint
71+
view.constrain(to: otherView).dimension(.width, to: .height, relation: .lessThanOrEqual, constant: 0, multiplier: 0.5, activate: false)
72+
73+
// Use the constraint builder returned after each newly created constraint to access the constraints created in order
74+
let constraint = view.constrain(to: otherView).dimension(.width, to: .height, constant: 0, priority: .defaultHigh, activate: false).constraints.last!
75+
constraint.isActive = true // activate the constraint later
76+
```
77+
*/
78+
public enum DimensionAnchor {
79+
case width, height
80+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// CGFloat+SystemSpacing.swift
3+
// SwiftLayout
4+
//
5+
// Created by Jake Sawyer on 11/27/18.
6+
// Copyright © 2018 it.swiftkick. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
public extension CGFloat {
12+
/**
13+
This value is only useful when using SwiftLayout to define a constraint that should use system spacing.
14+
It is a nonsense value of `-9999` in all other scenarios.
15+
16+
```
17+
// Constrain the leading anchors of both `view` and `otherView` by the system-determined appropriate spacing.
18+
view.constrain(to: otherView).leading(constant: .systemSpacing)
19+
```
20+
*/
21+
@available(iOS 11, *)
22+
public static var systemSpacing: CGFloat { return -9999 }
23+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//
2+
// Constrainable+Anchors.swift
3+
// SwiftLayout
4+
//
5+
// Created by Jake Sawyer on 11/27/18.
6+
// Copyright © 2018 it.swiftkick. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
// MARK: - Anchor Infos on Constrainable
12+
13+
extension Constrainable {
14+
var leadingAnchorInfo: AnchorInfo<NSLayoutXAxisAnchor> { return AnchorInfo(item: self, attribute: .leading, anchor: self.leadingAnchor) }
15+
var trailingAnchorInfo: AnchorInfo<NSLayoutXAxisAnchor> { return AnchorInfo(item: self, attribute: .trailing, anchor: self.trailingAnchor) }
16+
var topAnchorInfo: AnchorInfo<NSLayoutYAxisAnchor> { return AnchorInfo(item: self, attribute: .top, anchor: self.topAnchor) }
17+
var bottomAnchorInfo: AnchorInfo<NSLayoutYAxisAnchor> { return AnchorInfo(item: self, attribute: .bottom, anchor: self.bottomAnchor) }
18+
var widthAnchorInfo: AnchorInfo<NSLayoutDimension> { return AnchorInfo(item: self, attribute: .width, anchor: self.widthAnchor) }
19+
var heightAnchorInfo: AnchorInfo<NSLayoutDimension> { return AnchorInfo(item: self, attribute: .height, anchor: self.heightAnchor) }
20+
var centerXAnchorInfo: AnchorInfo<NSLayoutXAxisAnchor> { return AnchorInfo(item: self, attribute: .centerX, anchor: self.centerXAnchor) }
21+
var centerYAnchorInfo: AnchorInfo<NSLayoutYAxisAnchor> { return AnchorInfo(item: self, attribute: .centerY, anchor: self.centerYAnchor) }
22+
}
23+
24+
// MARK: - Getting AnchorInfos from enums
25+
26+
extension Constrainable {
27+
func anchorInfo(xAxis anchorType: XAxisAnchor) -> AnchorInfo<NSLayoutXAxisAnchor> {
28+
switch anchorType {
29+
case .leading: return leadingAnchorInfo
30+
case .trailing: return trailingAnchorInfo
31+
case .centerX: return centerXAnchorInfo
32+
}
33+
}
34+
35+
func anchorInfo(yAxis anchorType: YAxisAnchor) -> AnchorInfo<NSLayoutYAxisAnchor> {
36+
switch anchorType {
37+
case .top: return topAnchorInfo
38+
case .bottom: return bottomAnchorInfo
39+
case .centerY: return centerYAnchorInfo
40+
}
41+
}
42+
43+
func anchorInfo(dimension anchorType: DimensionAnchor) -> AnchorInfo<NSLayoutDimension> {
44+
switch anchorType {
45+
case .width: return widthAnchorInfo
46+
case .height: return heightAnchorInfo
47+
}
48+
}
49+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//
2+
// Constrainable+Builders.swift
3+
// SwiftLayout
4+
//
5+
// Created by Jake Sawyer on 11/27/18.
6+
// Copyright © 2018 it.swiftkick. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
public extension Constrainable {
12+
/**
13+
This method performs initial setup for constraining two `Constrainable`s together.
14+
In general, `UIView`s will have their autoresizing masks disabled, and will become children of the other `UIView` if they don't have one yet. Unowned `UILayoutGuide`s will have their owning views set.
15+
16+
# Setup process:
17+
- If this is a `UIView`, its `translatesAutoresizingMaskIntoConstraints` will be disabled.
18+
- If this is a `UIView` and doesn't yet have a superview, and the supplied constrainable is also a `UIView`, this view will become a child of the supplied view.
19+
- If this is a `UIView` and doesn't yet have a superview, and the supplied constrainable is a `UILayoutGuide` with an owning view, this view will become the child of the supplied layout guide's owning view.
20+
- If this is a `UILayoutGuide` and doesn't yet have an owning view, and the supplied constrainable is a `UIView`, this layout guide will be added to the supplied view.
21+
- If this is a `UILayoutGuide` and doesn't yet have an owning view, and the supplied constrainable is also a `UILayoutGuide` with an owning view, this layout guide will add itself to the supplied layout guide's owning view.
22+
23+
# Basic usage:
24+
```
25+
// Constrain both leading anchors for `view` and `otherView` with an equal relationship, constant of 0, multiplier of 1, and required priority.
26+
// The constraint is activated by default.
27+
view.constrain(to: otherView).leading()
28+
29+
// Constraint methods make heavy use of default arguments. You only need to specify arguments when setting specific values.
30+
view.constrain(to: otherView).width(.lessThanOrEqual, priority: .defaultLow)
31+
32+
// Some constraints invert their anchors so your constants can always be positive. This includes trailing and bottom constraints.
33+
// In this example, `view` is inset inside `otherView` by 8 points from the top and 24 points from the bottom.
34+
view.constrain(to: otherView).top(constant: 8).bottom(constant: 24)
35+
36+
// Chain method calls to create multiple constraints easily.
37+
view.constrain(to: otherView).top().bottom().width()
38+
```
39+
40+
# Advanced usage:
41+
```
42+
// Helper methods simplify common scenarios by defining multiple constraints at the same time.
43+
view.constrain(to: otherView).centerXY().widthHeight()
44+
45+
// Constrain a `view` to the `layoutMarginsGuide` of `otherView`, thus padding its edges inset from the safe areas and margins.
46+
view.constrain(to: otherView.layoutMarginsGuide).leadingTrailingTopBottom(constant: 32)
47+
48+
// Access the constraint builder once the constraints are made, and grab the constraints
49+
let builder = view.constrain(to: otherView).leadingTrailing(constant: 16).topBottom(constant: 8)
50+
print(builder.constraints) // constraints are supplied in order of declaration. In this case: leading, trailing, top, bottom.
51+
52+
// Create a highly customized constraint using system spacing, without activating it, and hold onto it for later use.
53+
let constraint = view.constrain(to: otherView).leading(.lessThanOrEqual, constant: .systemSpacing, multiplier: 0.5, priority: .defaultLow, activate: false).constraints.last!
54+
```
55+
*/
56+
@discardableResult
57+
func constrain(to constrainable: Constrainable) -> RelationalConstraintBuilder {
58+
return RelationalConstraintBuilder(first: self, second: constrainable)
59+
}
60+
61+
/**
62+
This method performs initial setup for distributing two `Constrainable`s vertically and/or horizontally via constraints.
63+
`UIView`s will have their autoresizing masks disabled and are assumed to already have superviews.
64+
`UILayoutGuide`s are assumed to already have owning views.
65+
66+
# Basic usage:
67+
```
68+
// Constrain `view` horizontally after `otherView` via `otherView.trailingAnchor` and `view.leadingAnchor`.
69+
view.constrain(after: otherView).leadingTrailing()
70+
```
71+
*/
72+
func constrain(after constrainable: Constrainable) -> DistributiveConstraintBuilder {
73+
return DistributiveConstraintBuilder(before: constrainable, after: self)
74+
}
75+
76+
/**
77+
This method performs initial setup for constraining a `Constrainable`'s width/height/aspect ratio.
78+
`UIView`s will have their autoresizing masks disabled.
79+
80+
- NOTE: `CGFloat.systemSpacing` is not an acceptable constant here.
81+
82+
# Basic usage:
83+
```
84+
// Constrain `view`'s width to 50 points
85+
view.constrainSelf().width(constant: 50)
86+
87+
// Constrain `view`'s width and height anchors to their intrinsic size at this moment
88+
view.constrainSelf().widthHeight(size: view.intrinsicContentSize)
89+
```
90+
*/
91+
func constrainSelf() -> SelfConstraintBuilder {
92+
return SelfConstraintBuilder(for: self)
93+
}
94+
}

0 commit comments

Comments
 (0)