Skip to content

Commit

Permalink
Merge branch 'main' into default-size
Browse files Browse the repository at this point in the history
  • Loading branch information
tinder-cfuller committed Feb 5, 2024
2 parents e8cb7a4 + 8ff5e2a commit 6f11db8
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 45 deletions.
2 changes: 2 additions & 0 deletions Plugins/SwiftLintCommand/SwiftLintCommand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ internal struct SwiftLintCommand: CommandPlugin {
break
case .uncaughtSignal:
return Diagnostics.error("Uncaught Signal")
@unknown default:
return Diagnostics.error("Unexpected Termination Reason")
}
guard process.terminationStatus == EXIT_SUCCESS
else { return Diagnostics.error("Command Failed") }
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ High Fidelity Auto Layout Result Builder Syntax for UIKit

## Overview

Tinder’s Layout library was introduced into the Tinder iOS codebase in 2017 and has since been used to programmatically define the screens of the Tinder iOS app.
Layout was introduced into the iOS codebase at Tinder in 2017 and has since been used to programmatically define the screens of the app.

Layout is a wrapper around the Apple provided Auto Layout SDK. Layout provides a less verbose syntax which aids in adoption and eases troubleshooting UI layout issues. Projects with large codebases use programmatic UI code instead of visual WYSIWYG editors (such as Xcode storyboards) to avoid unmanageable merge conflicts that occur in file formats such as XML (the serialized format of Xcode storyboards).
Layout is a wrapper around the Apple platform Auto Layout SDK and provides a less verbose DSL to aid in adoption and ease troubleshooting UI layout issues. Projects with large codebases use this type of programmatic UI code instead of visual WYSIWYG editors (such as Xcode storyboards) to avoid unmanageable merge conflicts that occur in file formats such as XML (the serialized format of Xcode storyboards).

Code written with Layout is declarative in nature such that it is easy to visualize the UI layout that the code represents. Layout does not limit the available Auto Layout capabilities in any way, which can readily be used along with the Layout API. In recent years, mobile platforms have seen the introduction of declarative UI frameworks such as SwiftUI and Jetpack Compose which realize significantly reduced learning curves. Layout takes a similar declarative approach but for the UIKit framework.
Code written with Layout leverages a high fidelity syntax, meaning it is easy to visualize the UI layout that the code represents. However, Layout does not limit the native Auto Layout capabilities in any way, which can readily be used along with the Layout API. In recent years, mobile platforms have seen the introduction of declarative UI frameworks such as SwiftUI and Jetpack Compose which realize significantly reduced learning curves. Layout also takes a declarative approach, in this case for the UIKit framework.

## Minimum Requirements

Expand Down
2 changes: 1 addition & 1 deletion Sources/Layout/UIKit/UIView+AutoLayout.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ extension UIView {
///
/// - Returns: The created constraint.
public func squareConstraint() -> NSLayoutConstraint {
constraint(for: .width, to: .height, of: self)
aspectRatioConstraint(1)
}

// MARK: - Aspect Ratio
Expand Down
86 changes: 46 additions & 40 deletions Tests/LayoutTests/UIKit/UIView+AutoLayoutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ final class UIViewAutoLayoutTests: XCTestCase {
// THEN

expect(view.translatesAutoresizingMaskIntoConstraints) == false
expect(view.constraints.first { $0.firstAttribute == .width }?.constant) == frame.width
expect(view.constraints.first { $0.firstAttribute == .height }?.constant) == frame.height
expect(view.constraints[0].constant) == frame.width
expect(view.constraints[1].constant) == frame.height
}

func testConstrainingSize() {
Expand All @@ -69,8 +69,8 @@ final class UIViewAutoLayoutTests: XCTestCase {
// THEN

expect(view.translatesAutoresizingMaskIntoConstraints) == false
expect(view.constraints.first { $0.firstAttribute == .width }?.constant) == size.width
expect(view.constraints.first { $0.firstAttribute == .height }?.constant) == size.height
expect(view.constraints[0].constant) == size.width
expect(view.constraints[1].constant) == size.height
}

func testConstrainingWidth_givenDefaults() {
Expand All @@ -91,7 +91,7 @@ final class UIViewAutoLayoutTests: XCTestCase {
// THEN

expect(view.translatesAutoresizingMaskIntoConstraints) == false
expect(view.constraints.first { $0.firstAttribute == .width }?.constant) == width
expect(view.constraints[0].constant) == width
}

func testConstrainingWidth() {
Expand All @@ -112,7 +112,7 @@ final class UIViewAutoLayoutTests: XCTestCase {
// THEN

expect(view.translatesAutoresizingMaskIntoConstraints) == false
expect(view.constraints.first { $0.firstAttribute == .width }?.constant) == width
expect(view.constraints[0].constant) == width
}

func testConstrainingHeight_givenDefaults() {
Expand All @@ -133,7 +133,7 @@ final class UIViewAutoLayoutTests: XCTestCase {
// THEN

expect(view.translatesAutoresizingMaskIntoConstraints) == false
expect(view.constraints.first { $0.firstAttribute == .height }?.constant) == height
expect(view.constraints[0].constant) == height
}

func testConstrainingHeight() {
Expand All @@ -154,11 +154,44 @@ final class UIViewAutoLayoutTests: XCTestCase {
// THEN

expect(view.translatesAutoresizingMaskIntoConstraints) == false
expect(view.constraints.first { $0.firstAttribute == .height }?.constant) == height
expect(view.constraints[0].constant) == height
}

// MARK: - Size

func testSizeConstraintsWithSize() {

// GIVEN

let view: UIView = .init(frame: CGRect(x: 0, y: 0, width: 10, height: 20))

// WHEN

let sizeConstraints1: [NSLayoutConstraint] = view.sizeConstraints()

// THEN

expect(sizeConstraints1.count) == 2
expect(sizeConstraints1[0].firstAttribute) == .width
expect(sizeConstraints1[0].constant) == 10
expect(sizeConstraints1[1].firstAttribute) == .height
expect(sizeConstraints1[1].constant) == 20

// WHEN

let sizeConstraints2: [NSLayoutConstraint] = view.sizeConstraints(.init(width: 10, height: 20))

// THEN

expect(sizeConstraints2.count) == 2
expect(sizeConstraints2[0].firstAttribute) == .width
expect(sizeConstraints2[0].constant) == 10
expect(sizeConstraints2[1].firstAttribute) == .height
expect(sizeConstraints2[1].constant) == 20
}

// MARK: - Width

func testWidthConstraintIsRelationToConstant() {

// GIVEN
Expand Down Expand Up @@ -231,6 +264,8 @@ final class UIViewAutoLayoutTests: XCTestCase {
expect(widthConstraint2.constant) == width2
}

// MARK: - Height

func testHeightConstraintIsRelationToConstant() {

// GIVEN
Expand Down Expand Up @@ -303,38 +338,7 @@ final class UIViewAutoLayoutTests: XCTestCase {
expect(heightConstraint2.constant) == height2
}

func testSizeConstraintsWithSize() {

// GIVEN

let view: UIView = .init(frame: CGRect(x: 0, y: 0, width: 10, height: 20))

// WHEN

let sizeConstraints1: [NSLayoutConstraint] = view.sizeConstraints()

// THEN

expect(sizeConstraints1.count) == 2
expect(sizeConstraints1[0].firstAttribute) == .width
expect(sizeConstraints1[0].constant) == 10
expect(sizeConstraints1[1].firstAttribute) == .height
expect(sizeConstraints1[1].constant) == 20

// WHEN

let sizeConstraints2: [NSLayoutConstraint] = view.sizeConstraints(.init(width: 10, height: 20))

// THEN

expect(sizeConstraints2.count) == 2
expect(sizeConstraints2[0].firstAttribute) == .width
expect(sizeConstraints2[0].constant) == 10
expect(sizeConstraints2[1].firstAttribute) == .height
expect(sizeConstraints2[1].constant) == 20
}

// MARK: - Aspect Ratio
// MARK: - Square

func testSquareConstraint() {

Expand All @@ -353,6 +357,8 @@ final class UIViewAutoLayoutTests: XCTestCase {
expect(constraint.relation) == .equal
}

// MARK: - Aspect Ratio

func testAspectRatioConstraintWithRatio() {

// GIVEN
Expand Down
5 changes: 4 additions & 1 deletion cheatsheet.html
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,11 @@ <h3>Height</h3>
to: 100,
priority: .high)</pre>
<h3>Square</h3>
<pre>// Shape //</pre>
<pre>square(100)</pre>
<pre>square(100, priority: .high)</pre>
<pre>square() // square aspect ratio</pre>
<pre>// Aspect Ratio //</pre>
<pre>square()</pre>
<h3>Aspect Ratio</h3>
<pre>aspectRatio(0.5)</pre>
<pre>aspectRatio(0.5, priority: .high)</pre>
Expand Down Expand Up @@ -283,6 +285,7 @@ <h3>Height</h3>
<pre>heightConstraint()</pre>
<pre>heightConstraint(100)</pre>
<h3>Square</h3>
<pre>// Aspect Ratio //</pre>
<pre>squareConstraint()</pre>
<h3>Aspect Ratio</h3>
<pre>aspectRatioConstraint(0.5)</pre>
Expand Down

0 comments on commit 6f11db8

Please sign in to comment.