From 0cfab586f7982c1aa54568c5d21b40331b820d50 Mon Sep 17 00:00:00 2001 From: Christopher Fuller Date: Fri, 19 Jan 2024 14:20:20 -0800 Subject: [PATCH] Reorder methods and add pragma marked sections (#288) * Reorder methods and add pragma marked sections * Fix SwiftLint violations --- Sources/Layout/Swift/Array.swift | 4 + Sources/Layout/UIKit/NSLayoutConstraint.swift | 6 +- Sources/Layout/UIKit/UIView+AutoLayout.swift | 188 +++++++------ Tests/LayoutTests/Swift/ArrayTests.swift | 4 + .../UIKit/NSLayoutConstraintTests.swift | 76 ++--- .../UIKit/UIView+AutoLayoutTests.swift | 264 +++++++++--------- 6 files changed, 290 insertions(+), 252 deletions(-) diff --git a/Sources/Layout/Swift/Array.swift b/Sources/Layout/Swift/Array.swift index 2ded66be..fd4a59a0 100644 --- a/Sources/Layout/Swift/Array.swift +++ b/Sources/Layout/Swift/Array.swift @@ -11,6 +11,8 @@ import UIKit extension Array where Element == NSLayoutConstraint { + // MARK: - Activation + /// Activates the constraints in the array. /// /// - Returns: The activated constraints. @@ -33,6 +35,8 @@ extension Array where Element == NSLayoutConstraint { return self } + // MARK: - Priority + /// Sets the priority of the constraints in the array to required. /// /// - Returns: The required constraints. diff --git a/Sources/Layout/UIKit/NSLayoutConstraint.swift b/Sources/Layout/UIKit/NSLayoutConstraint.swift index 2086659e..7540b2df 100644 --- a/Sources/Layout/UIKit/NSLayoutConstraint.swift +++ b/Sources/Layout/UIKit/NSLayoutConstraint.swift @@ -11,7 +11,7 @@ import UIKit extension NSLayoutConstraint { - // MARK: - VFL Convenience APIs + // MARK: - Visual Format Language /// Creates constraints described by a visual format string. /// @@ -49,7 +49,7 @@ extension NSLayoutConstraint { formats.flatMap { constraints(format: $0, views: views, metrics: metrics, options: options) } } - // MARK: - Mutators + // MARK: - Activation /// Activates the constraint. /// @@ -69,6 +69,8 @@ extension NSLayoutConstraint { return self } + // MARK: - Priority + /// Sets the priority of the constraint to required. /// /// - Returns: The required constraint. diff --git a/Sources/Layout/UIKit/UIView+AutoLayout.swift b/Sources/Layout/UIKit/UIView+AutoLayout.swift index 5e882bf2..ea4a3510 100644 --- a/Sources/Layout/UIKit/UIView+AutoLayout.swift +++ b/Sources/Layout/UIKit/UIView+AutoLayout.swift @@ -11,7 +11,7 @@ import UIKit extension UIView { - // MARK: - Constraint Builders + // MARK: - Builder /// Require the layout of the view be determined by adding constraints. /// @@ -54,10 +54,106 @@ extension UIView { return usingConstraints() } - // MARK: - Constraint Factories + // MARK: - Size + + /// Creates a constraint defining the width of the receiver. + /// + /// - Parameters: + /// - relation: The relationship between the width and constant value. + /// - constant: The constant width value. When `nil`, the width of the receiver is used. + /// + /// - Returns: The created constraint. + public func widthConstraint( + is relation: NSLayoutConstraint.Relation = .equal, + constant: CGFloat? = nil + ) -> NSLayoutConstraint { + width.constraint(is: relation, constant: constant ?? bounds.width) + } + + /// Creates a constraint defining the height of the receiver. + /// + /// - Parameters: + /// - relation: The relationship between the height and constant value. + /// - constant: The constant height value. When `nil`, the height of the receiver is used. + /// + /// - Returns: The created constraint. + public func heightConstraint( + is relation: NSLayoutConstraint.Relation = .equal, + constant: CGFloat? = nil + ) -> NSLayoutConstraint { + height.constraint(is: relation, constant: constant ?? bounds.height) + } + + /// Creates constraints defining the size of the receiver. + /// + /// - Parameter size: The constant size value. When `nil`, the size of the receiver is used. + /// + /// - Returns: The created constraints. + public func sizeConstraints( + _ size: CGSize? = nil + ) -> [NSLayoutConstraint] { + [ + width.constraint(constant: size?.width ?? bounds.width), + height.constraint(constant: size?.height ?? bounds.height) + ] + } + + // MARK: - Aspect Ratio + + /// Creates a constraint defining the aspect ratio of the receiver to be square. + /// + /// - Returns: The created constraint. + public func squareConstraint() -> NSLayoutConstraint { + constraint(for: .width, to: .height, of: self) + } + + /// Creates a constraint defining the aspect ratio of the receiver. + /// + /// - Parameter ratio: The aspect ratio. + /// + /// - Returns: The created constraint. + public func aspectRatioConstraint( + _ ratio: CGFloat + ) -> NSLayoutConstraint { + constraint(for: .width, to: .height, of: self, multiplier: ratio) + } + + // MARK: - Equal + + /// Creates constraints between the given attribute of the receiver and target views. + /// + /// - Parameters: + /// - attribute: The attribute to constrain. + /// - views: The views to constrain to the receiver. + /// + /// - Returns: The created constraints. + public func equalConstraints( + for attribute: NSLayoutConstraint.Attribute, + to views: [UIView] + ) -> [NSLayoutConstraint] { + views.map { constraint(to: attribute, of: $0) } + } + + // MARK: - Center + + /// Creates constraints to the center of the superview of the receiver with an offset. + /// + /// - Parameter offset: The offset amount. + /// + /// - Returns: The created constraints. + public func centerConstraints( + offset: UIOffset = .zero + ) -> [NSLayoutConstraint] { + [ + constraint(toSuperview: .centerX, constant: offset.horizontal), + constraint(toSuperview: .centerY, constant: offset.vertical) + ] + } // swiftlint:disable function_default_parameter_at_end + // MARK: - Attributes + /// Creates a constraint defining the relationship between the given attribute of the receiver and superview. /// /// The `superviewAttribute` will be used as the attribute of the receiver if `attribute` is not provided. @@ -168,65 +264,7 @@ extension UIView { // swiftlint:enable function_default_parameter_at_end - /// Creates a constraint defining the width of the receiver. - /// - /// - Parameters: - /// - relation: The relationship between the width and constant value. - /// - constant: The constant width value. When `nil`, the width of the receiver is used. - /// - /// - Returns: The created constraint. - public func widthConstraint( - is relation: NSLayoutConstraint.Relation = .equal, - constant: CGFloat? = nil - ) -> NSLayoutConstraint { - width.constraint(is: relation, constant: constant ?? bounds.width) - } - - /// Creates a constraint defining the height of the receiver. - /// - /// - Parameters: - /// - relation: The relationship between the height and constant value. - /// - constant: The constant height value. When `nil`, the height of the receiver is used. - /// - /// - Returns: The created constraint. - public func heightConstraint( - is relation: NSLayoutConstraint.Relation = .equal, - constant: CGFloat? = nil - ) -> NSLayoutConstraint { - height.constraint(is: relation, constant: constant ?? bounds.height) - } - - /// Creates constraints defining the size of the receiver. - /// - /// - Parameter size: The constant size value. When `nil`, the size of the receiver is used. - /// - /// - Returns: The created constraints. - public func sizeConstraints( - _ size: CGSize? = nil - ) -> [NSLayoutConstraint] { - [ - width.constraint(constant: size?.width ?? bounds.width), - height.constraint(constant: size?.height ?? bounds.height) - ] - } - - /// Creates a constraint defining the aspect ratio of the receiver to be square. - /// - /// - Returns: The created constraint. - public func squareConstraint() -> NSLayoutConstraint { - constraint(for: .width, to: .height, of: self) - } - - /// Creates a constraint defining the aspect ratio of the receiver. - /// - /// - Parameter ratio: The aspect ratio. - /// - /// - Returns: The created constraint. - public func aspectRatioConstraint( - _ ratio: CGFloat - ) -> NSLayoutConstraint { - constraint(for: .width, to: .height, of: self, multiplier: ratio) - } + // MARK: - Edges /// Creates constraints to the edges of the superview of the receiver with an inset. /// @@ -270,32 +308,4 @@ extension UIView { constraint(toSuperview: .right, constant: -insets.right) ] } - - /// Creates constraints to the center of the superview of the receiver with an offset. - /// - /// - Parameter offset: The offset amount. - /// - /// - Returns: The created constraints. - public func centerConstraints( - offset: UIOffset = .zero - ) -> [NSLayoutConstraint] { - [ - constraint(toSuperview: .centerX, constant: offset.horizontal), - constraint(toSuperview: .centerY, constant: offset.vertical) - ] - } - - /// Creates constraints between the given attribute of the receiver and target views. - /// - /// - Parameters: - /// - attribute: The attribute to constrain. - /// - views: The views to constrain to the receiver. - /// - /// - Returns: The created constraints. - public func equalConstraints( - for attribute: NSLayoutConstraint.Attribute, - to views: [UIView] - ) -> [NSLayoutConstraint] { - views.map { constraint(to: attribute, of: $0) } - } } diff --git a/Tests/LayoutTests/Swift/ArrayTests.swift b/Tests/LayoutTests/Swift/ArrayTests.swift index cde5e85c..7af58323 100644 --- a/Tests/LayoutTests/Swift/ArrayTests.swift +++ b/Tests/LayoutTests/Swift/ArrayTests.swift @@ -14,6 +14,8 @@ import XCTest @MainActor final class ArrayTests: XCTestCase { + // MARK: - Activation + func testActivation() { // GIVEN @@ -65,6 +67,8 @@ final class ArrayTests: XCTestCase { expect(deactivatedConstraints) == constraints } + // MARK: - Priority + func testRequire() { // GIVEN diff --git a/Tests/LayoutTests/UIKit/NSLayoutConstraintTests.swift b/Tests/LayoutTests/UIKit/NSLayoutConstraintTests.swift index 4ceb2305..2757b59e 100644 --- a/Tests/LayoutTests/UIKit/NSLayoutConstraintTests.swift +++ b/Tests/LayoutTests/UIKit/NSLayoutConstraintTests.swift @@ -14,41 +14,7 @@ import XCTest @MainActor final class NSLayoutConstraintTests: XCTestCase { - func testActivation() { - - // GIVEN - - let view: UIView = .init() - let constraint: NSLayoutConstraint = .init( - item: view, - attribute: .height, - relatedBy: .equal, - toItem: nil, - attribute: .notAnAttribute, - multiplier: 1, - constant: 0 - ) - - // THEN - - expect(constraint.isActive) == false - - // WHEN - - constraint.activate() - - // THEN - - expect(constraint.isActive) == true - - // WHEN - - constraint.deactivate() - - // THEN - - expect(constraint.isActive) == false - } + // MARK: - Visual Format Language func testConstraintsWithVisualFormatLanguage() { @@ -108,6 +74,46 @@ final class NSLayoutConstraintTests: XCTestCase { } } + // MARK: - Activation + + func testActivation() { + + // GIVEN + + let view: UIView = .init() + let constraint: NSLayoutConstraint = .init( + item: view, + attribute: .height, + relatedBy: .equal, + toItem: nil, + attribute: .notAnAttribute, + multiplier: 1, + constant: 0 + ) + + // THEN + + expect(constraint.isActive) == false + + // WHEN + + constraint.activate() + + // THEN + + expect(constraint.isActive) == true + + // WHEN + + constraint.deactivate() + + // THEN + + expect(constraint.isActive) == false + } + + // MARK: - Priority + func testRequire() { // GIVEN diff --git a/Tests/LayoutTests/UIKit/UIView+AutoLayoutTests.swift b/Tests/LayoutTests/UIKit/UIView+AutoLayoutTests.swift index 8bab0b4c..0816d3a1 100644 --- a/Tests/LayoutTests/UIKit/UIView+AutoLayoutTests.swift +++ b/Tests/LayoutTests/UIKit/UIView+AutoLayoutTests.swift @@ -15,7 +15,7 @@ import XCTest final class UIViewAutoLayoutTests: XCTestCase { - // MARK: - Tests + // MARK: - Builder func testUsingConstraints() { @@ -156,77 +156,7 @@ final class UIViewAutoLayoutTests: XCTestCase { expect(view.constraints.first { $0.firstAttribute == .height }?.constant) == height } - func testConstraintToSuperview() { - - // GIVEN - - let superview: UIView = .init() - let view: UIView = .init() - superview.addSubview(view) - - // WHEN - - let constraints1: [NSLayoutConstraint] = view.constraints(toSuperview: [.top]) - - // THEN - - expect(constraints1.first?.firstAttribute) == .top - expect(constraints1.first?.relation) == .equal - expect(constraints1.first?.multiplier) == 1 - expect(constraints1.first?.constant) == 0 - - // WHEN - - let constraints2: [NSLayoutConstraint] = view.constraints( - is: .greaterThanOrEqual, - toSuperview: [.bottom], - multiplier: 2, - constant: 5 - ) - - // THEN - - expect(constraints2.first?.firstAttribute) == .bottom - expect(constraints2.first?.relation) == .greaterThanOrEqual - expect(constraints2.first?.multiplier) == 2 - expect(constraints2.first?.constant) == 5 - } - - func testConstraintToTargetView() { - - // GIVEN - - let view: UIView = .init() - let targetView: UIView = .init() - - // WHEN - - let constraints1: [NSLayoutConstraint] = view.constraints(to: [.top], of: targetView) - - // THEN - - expect(constraints1.first?.firstAttribute) == .top - expect(constraints1.first?.relation) == .equal - expect(constraints1.first?.multiplier) == 1 - expect(constraints1.first?.constant) == 0 - - // WHEN - - let constraints2: [NSLayoutConstraint] = view.constraints( - is: .greaterThanOrEqual, - to: [.bottom], - of: targetView, - multiplier: 2, - constant: 5 - ) - - // THEN - - expect(constraints2.first?.firstAttribute) == .bottom - expect(constraints2.first?.relation) == .greaterThanOrEqual - expect(constraints2.first?.multiplier) == 2 - expect(constraints2.first?.constant) == 5 - } + // MARK: - Size func testWidthConstraint() { @@ -344,6 +274,8 @@ final class UIViewAutoLayoutTests: XCTestCase { expect(sizeConstraints2[1].constant) == 20 } + // MARK: - Aspect Ratio + func testSquareConstraint() { // GIVEN @@ -380,6 +312,140 @@ final class UIViewAutoLayoutTests: XCTestCase { expect(constraint.multiplier) == ratio } + // MARK: - Equal + + func testEqualConstraints() { + + // GIVEN + + let superview: UIView = .init() + let view: UIView = .init() + + // WHEN + + let constraints: [NSLayoutConstraint] = view.equalConstraints(for: .top, to: [superview]) + + // THEN + + expect(constraints.first?.firstAttribute) == .top + expect(constraints.first?.relation) == .equal + } + + // MARK: - Center + + func testCenterConstraints() { + + // GIVEN + + let superview: UIView = .init() + let view: UIView = .init() + superview.addSubview(view) + + // WHEN + + let constraints1: [NSLayoutConstraint] = view.centerConstraints() + + // THEN + + expect(constraints1.count) == 2 + expect(constraints1[0].firstAttribute) == .centerX + expect(constraints1[0].constant) == 0 + expect(constraints1[1].firstAttribute) == .centerY + expect(constraints1[1].constant) == 0 + + // GIVEN + + let offset: UIOffset = .init(horizontal: 5, vertical: 10) + + // WHEN + + let constraints2: [NSLayoutConstraint] = view.centerConstraints(offset: offset) + + // THEN + + expect(constraints2.count) == 2 + expect(constraints2[0].firstAttribute) == .centerX + expect(constraints2[0].constant) == offset.horizontal + expect(constraints2[1].firstAttribute) == .centerY + expect(constraints2[1].constant) == offset.vertical + } + + // MARK: - Attributes + + func testConstraintToSuperview() { + + // GIVEN + + let superview: UIView = .init() + let view: UIView = .init() + superview.addSubview(view) + + // WHEN + + let constraints1: [NSLayoutConstraint] = view.constraints(toSuperview: [.top]) + + // THEN + + expect(constraints1.first?.firstAttribute) == .top + expect(constraints1.first?.relation) == .equal + expect(constraints1.first?.multiplier) == 1 + expect(constraints1.first?.constant) == 0 + + // WHEN + + let constraints2: [NSLayoutConstraint] = view.constraints( + is: .greaterThanOrEqual, + toSuperview: [.bottom], + multiplier: 2, + constant: 5 + ) + + // THEN + + expect(constraints2.first?.firstAttribute) == .bottom + expect(constraints2.first?.relation) == .greaterThanOrEqual + expect(constraints2.first?.multiplier) == 2 + expect(constraints2.first?.constant) == 5 + } + + func testConstraintToTargetView() { + + // GIVEN + + let view: UIView = .init() + let targetView: UIView = .init() + + // WHEN + + let constraints1: [NSLayoutConstraint] = view.constraints(to: [.top], of: targetView) + + // THEN + + expect(constraints1.first?.firstAttribute) == .top + expect(constraints1.first?.relation) == .equal + expect(constraints1.first?.multiplier) == 1 + expect(constraints1.first?.constant) == 0 + + // WHEN + + let constraints2: [NSLayoutConstraint] = view.constraints( + is: .greaterThanOrEqual, + to: [.bottom], + of: targetView, + multiplier: 2, + constant: 5 + ) + + // THEN + + expect(constraints2.first?.firstAttribute) == .bottom + expect(constraints2.first?.relation) == .greaterThanOrEqual + expect(constraints2.first?.multiplier) == 2 + expect(constraints2.first?.constant) == 5 + } + + // MARK: - Edges + func testEdgeConstraints() { // GIVEN @@ -482,58 +548,4 @@ final class UIViewAutoLayoutTests: XCTestCase { expect(constraints[3].firstAttribute) == .right expect(constraints[3].constant) == -insets.right } - - func testCenterConstraints() { - - // GIVEN - - let superview: UIView = .init() - let view: UIView = .init() - superview.addSubview(view) - - // WHEN - - let constraints1: [NSLayoutConstraint] = view.centerConstraints() - - // THEN - - expect(constraints1.count) == 2 - expect(constraints1[0].firstAttribute) == .centerX - expect(constraints1[0].constant) == 0 - expect(constraints1[1].firstAttribute) == .centerY - expect(constraints1[1].constant) == 0 - - // GIVEN - - let offset: UIOffset = .init(horizontal: 5, vertical: 10) - - // WHEN - - let constraints2: [NSLayoutConstraint] = view.centerConstraints(offset: offset) - - // THEN - - expect(constraints2.count) == 2 - expect(constraints2[0].firstAttribute) == .centerX - expect(constraints2[0].constant) == offset.horizontal - expect(constraints2[1].firstAttribute) == .centerY - expect(constraints2[1].constant) == offset.vertical - } - - func testEqualConstraints() { - - // GIVEN - - let superview: UIView = .init() - let view: UIView = .init() - - // WHEN - - let constraints: [NSLayoutConstraint] = view.equalConstraints(for: .top, to: [superview]) - - // THEN - - expect(constraints.first?.firstAttribute) == .top - expect(constraints.first?.relation) == .equal - } }