From c0cf2a2a8c94c52b96cb699dd231cefac297355b Mon Sep 17 00:00:00 2001 From: Jakub Kiermasz Date: Sat, 11 Nov 2023 14:40:56 +0100 Subject: [PATCH] Add LayoutGuide relevant DimensionalLayout --- .../AnchorLayout/DimensionLayout.swift | 18 +++ ...ideLayout+LayoutGuideDimensionLayout.swift | 37 +++++- ...ltLayoutResult+ResultDimensionLayout.swift | 16 ++- .../UIViewLayout+ViewDimensionLayout.swift | 17 ++- ...utGuideLayout+Layout+Dimension+Tests.swift | 108 ++++++++++++++-- Tests/NeronTests/TestClasses/TestView.swift | 9 +- .../ViewLayout+Layout+Dimension+Tests.swift | 116 +++++++++++++++--- 7 files changed, 283 insertions(+), 38 deletions(-) diff --git a/Sources/Neron/Contracts/AnchorLayout/DimensionLayout.swift b/Sources/Neron/Contracts/AnchorLayout/DimensionLayout.swift index 51e8a63..be2be76 100644 --- a/Sources/Neron/Contracts/AnchorLayout/DimensionLayout.swift +++ b/Sources/Neron/Contracts/AnchorLayout/DimensionLayout.swift @@ -31,6 +31,15 @@ public protocol DimensionLayout { @discardableResult func greaterThanOrEqualTo(_ sibling: UIView, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + @discardableResult + func equalTo(_ layoutGuide: UILayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + + @discardableResult + func lessThanOrEqualTo(_ layoutGuide: UILayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + + @discardableResult + func greaterThanOrEqualTo(_ layoutGuide: UILayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + #else @discardableResult @@ -42,6 +51,15 @@ public protocol DimensionLayout { @discardableResult func greaterThanOrEqualTo(_ sibling: NSView, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + @discardableResult + func equalTo(_ layoutGuide: NSLayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + + @discardableResult + func lessThanOrEqualTo(_ layoutGuide: NSLayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + + @discardableResult + func greaterThanOrEqualTo(_ layoutGuide: NSLayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier + #endif } diff --git a/Sources/Neron/LayoutGuideLayout/AnchorLayout/LayoutGuideLayout+LayoutGuideDimensionLayout.swift b/Sources/Neron/LayoutGuideLayout/AnchorLayout/LayoutGuideLayout+LayoutGuideDimensionLayout.swift index ddc15a6..11915ba 100644 --- a/Sources/Neron/LayoutGuideLayout/AnchorLayout/LayoutGuideLayout+LayoutGuideDimensionLayout.swift +++ b/Sources/Neron/LayoutGuideLayout/AnchorLayout/LayoutGuideLayout+LayoutGuideDimensionLayout.swift @@ -12,7 +12,7 @@ extension LayoutGuideLayout { final class LayoutGuideDimensionLayout: DimensionLayout { - + // MARK: - Properties private let anchor: LayoutAnchor.Dimension @@ -47,7 +47,11 @@ extension LayoutGuideLayout { } func equalTo(_ sibling: View, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { - let constraint = LayoutConstraint(item: layoutGuide, itemAttribute: self.anchor.attribute, relation: .equal, target: sibling, targetAttribute: anchor.attribute) + let constraint = LayoutConstraint(item: layoutGuide, + itemAttribute: self.anchor.attribute, + relation: .equal, + target: sibling, + targetAttribute: anchor.attribute) return makePrioritizer(for: endorse(constraint)) } @@ -68,7 +72,34 @@ extension LayoutGuideLayout { targetAttribute: anchor.attribute) return makePrioritizer(for: endorse(constraint)) } - + + func equalTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + let constraint = LayoutConstraint(item: self.layoutGuide, + itemAttribute: self.anchor.attribute, + relation: .equal, + target: layoutGuide, + targetAttribute: anchor.attribute) + return makePrioritizer(for: endorse(constraint)) + } + + func lessThanOrEqualTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + let constraint = LayoutConstraint(item: self.layoutGuide, + itemAttribute: self.anchor.attribute, + relation: .lessThanOrEqual, + target: layoutGuide, + targetAttribute: anchor.attribute) + return makePrioritizer(for: endorse(constraint)) + } + + func greaterThanOrEqualTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + let constraint = LayoutConstraint(item: self.layoutGuide, + itemAttribute: self.anchor.attribute, + relation: .greaterThanOrEqual, + target: layoutGuide, + targetAttribute: anchor.attribute) + return makePrioritizer(for: endorse(constraint)) + } + // MARK: - Private private func endorse(_ constraint: LayoutConstraint) -> LayoutConstraint { diff --git a/Sources/Neron/LayoutResult/AnchorLayout/DefaultLayoutResult+ResultDimensionLayout.swift b/Sources/Neron/LayoutResult/AnchorLayout/DefaultLayoutResult+ResultDimensionLayout.swift index bd459bd..010cc6a 100644 --- a/Sources/Neron/LayoutResult/AnchorLayout/DefaultLayoutResult+ResultDimensionLayout.swift +++ b/Sources/Neron/LayoutResult/AnchorLayout/DefaultLayoutResult+ResultDimensionLayout.swift @@ -12,7 +12,7 @@ extension DefaultLayoutResult { final class ResultDimensionLayout: DimensionLayout { - + // MARK: - Properties private let anchor: LayoutAnchor.Dimension @@ -57,7 +57,19 @@ extension DefaultLayoutResult { func greaterThanOrEqualTo(_ sibling: View, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { invokerLayout.greaterThanOrEqualTo(sibling, anchor) } - + + func equalTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + invokerLayout.equalTo(layoutGuide, anchor) + } + + func lessThanOrEqualTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + invokerLayout.lessThanOrEqualTo(layoutGuide, anchor) + } + + func greaterThanOrEqualTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + invokerLayout.greaterThanOrEqualTo(layoutGuide, anchor) + } + } } diff --git a/Sources/Neron/ViewLayout/AnchorLayout/UIViewLayout+ViewDimensionLayout.swift b/Sources/Neron/ViewLayout/AnchorLayout/UIViewLayout+ViewDimensionLayout.swift index 08de935..4fefe2c 100644 --- a/Sources/Neron/ViewLayout/AnchorLayout/UIViewLayout+ViewDimensionLayout.swift +++ b/Sources/Neron/ViewLayout/AnchorLayout/UIViewLayout+ViewDimensionLayout.swift @@ -60,7 +60,22 @@ extension ViewLayout { let constraint = LayoutConstraint(item: view, itemAttribute: self.anchor.attribute, relation: .greaterThanOrEqual, target: sibling, targetAttribute: anchor.attribute) return makePrioritizer(for: endorse(constraint)) } - + + func equalTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + let constraint = LayoutConstraint(item: view, itemAttribute: self.anchor.attribute, relation: .equal, target: layoutGuide, targetAttribute: anchor.attribute) + return makePrioritizer(for: endorse(constraint)) + } + + func lessThanOrEqualTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + let constraint = LayoutConstraint(item: view, itemAttribute: self.anchor.attribute, relation: .lessThanOrEqual, target: layoutGuide, targetAttribute: anchor.attribute) + return makePrioritizer(for: endorse(constraint)) + } + + func greaterThanOrEqualTo(_ layoutGuide: LayoutGuide, _ anchor: LayoutAnchor.Dimension) -> ConstraintMultiplier { + let constraint = LayoutConstraint(item: view, itemAttribute: self.anchor.attribute, relation: .greaterThanOrEqual, target: layoutGuide, targetAttribute: anchor.attribute) + return makePrioritizer(for: endorse(constraint)) + } + // MARK: - Private private func endorse(_ constraint: LayoutConstraint) -> LayoutConstraint { diff --git a/Tests/NeronTests/LayoutGuideLayout/LayoutGuideLayout+Layout+Dimension+Tests.swift b/Tests/NeronTests/LayoutGuideLayout/LayoutGuideLayout+Layout+Dimension+Tests.swift index a88be58..f4885ce 100644 --- a/Tests/NeronTests/LayoutGuideLayout/LayoutGuideLayout+Layout+Dimension+Tests.swift +++ b/Tests/NeronTests/LayoutGuideLayout/LayoutGuideLayout+Layout+Dimension+Tests.swift @@ -60,7 +60,6 @@ final class LayoutGuideLayout_Layout_Dimension_Tests: XCTestCase { func test_height_EqualToSibling() { let guide = LayoutGuide() - print(parent.frame) let constraint = guide.layout .add(to: parent) .height.equalTo(parent, .height) @@ -73,30 +72,73 @@ final class LayoutGuideLayout_Layout_Dimension_Tests: XCTestCase { func test_height_LessThanOrEqualToSibling() { let guide = LayoutGuide() - print(parent.frame) let constraint = guide.layout .add(to: parent) - .height.equalTo(parent, .height) + .height.lessThanOrEqualTo(parent, .height) .activate() .constraint parent.prepare() XCTAssertLessThanOrEqual(guide.frame.height, 200, "Height should be 200") - XCTAssertEqual(constraint.relation, .equal, "Relation should be lessThanOrEqual") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") } func test_height_GreaterThanOrEqualToSibling() { let guide = LayoutGuide() - print(parent.frame) let constraint = guide.layout .add(to: parent) - .height.equalTo(parent, .height) + .height.greaterThanOrEqualTo(parent, .height) .activate() .constraint parent.prepare() XCTAssertGreaterThanOrEqual(guide.frame.height, 200, "Height should be 200") - XCTAssertEqual(constraint.relation, .equal, "Relation should be greaterThanOrEqual") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") } - + + func test_Height_EqualToLayoutGuide() { + let height: CGFloat = 150 + let parent = TestView(height: height) + let parentGuide = parent.layoutGuide + let guide = LayoutGuide() + let constraint = guide.layout + .add(to: parent) + .height.equalTo(parentGuide, .height) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(guide.frame.height, height, "Height should be \(height)") + XCTAssertEqual(constraint.relation, .equal, "Relation should be equal") + } + + func test_Height_LessThanOrEqualToLayoutGuide() { + let height: CGFloat = 150 + let parent = TestView(height: height) + let parentGuide = parent.layoutGuide + let guide = LayoutGuide() + let constraint = guide.layout + .add(to: parent) + .height.lessThanOrEqualTo(parentGuide, .height) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(guide.frame.height, height, "Height should be \(height)") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") + } + + func test_Height_GreaterThanOrEqualToLayoutGuide() { + let height: CGFloat = 150 + let parent = TestView(height: height) + let parentGuide = parent.layoutGuide + let guide = LayoutGuide() + let constraint = guide.layout + .add(to: parent) + .height.greaterThanOrEqualTo(parentGuide, .height) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(guide.frame.height, height, "Height should be \(height)") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") + } + // MARK: - Width func test_width_EqualToConstant() { @@ -137,7 +179,6 @@ final class LayoutGuideLayout_Layout_Dimension_Tests: XCTestCase { func test_width_EqualToSibling() { let guide = LayoutGuide() - print(parent.frame) let constraint = guide.layout .add(to: parent) .width.equalTo(parent, .width) @@ -150,7 +191,6 @@ final class LayoutGuideLayout_Layout_Dimension_Tests: XCTestCase { func test_width_LessThanOrEqualToSibling() { let guide = LayoutGuide() - print(parent.frame) let constraint = guide.layout .add(to: parent) .width.equalTo(parent, .width) @@ -163,7 +203,6 @@ final class LayoutGuideLayout_Layout_Dimension_Tests: XCTestCase { func test_width_GreaterThanOrEqualToSibling() { let guide = LayoutGuide() - print(parent.frame) let constraint = guide.layout .add(to: parent) .width.equalTo(parent, .width) @@ -173,5 +212,50 @@ final class LayoutGuideLayout_Layout_Dimension_Tests: XCTestCase { XCTAssertGreaterThanOrEqual(guide.frame.width, 200, "Width should be 200") XCTAssertEqual(constraint.relation, .equal, "Relation should be greaterThanOrEqual") } - + + func test_Width_EqualToLayoutGuide() { + let width: CGFloat = 150 + let parent = TestView(width: width) + let parentGuide = parent.layoutGuide + let guide = LayoutGuide() + let constraint = guide.layout + .add(to: parent) + .width.equalTo(parentGuide, .width) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(guide.frame.width, width, "Width should be \(width)") + XCTAssertEqual(constraint.relation, .equal, "Relation should be equal") + } + + func test_Width_LessThanOrEqualToLayoutGuide() { + let width: CGFloat = 150 + let parent = TestView(width: width) + let parentGuide = parent.layoutGuide + let guide = LayoutGuide() + let constraint = guide.layout + .add(to: parent) + .width.lessThanOrEqualTo(parentGuide, .width) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(guide.frame.width, width, "Width should be \(width)") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") + } + + func test_Width_GreaterThanOrEqualToLayoutGuide() { + let width: CGFloat = 150 + let parent = TestView(width: width) + let parentGuide = parent.layoutGuide + let guide = LayoutGuide() + let constraint = guide.layout + .add(to: parent) + .width.greaterThanOrEqualTo(parentGuide, .width) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(guide.frame.width, width, "Width should be \(width)") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") + } + } diff --git a/Tests/NeronTests/TestClasses/TestView.swift b/Tests/NeronTests/TestClasses/TestView.swift index 8e9411f..0ad7f1a 100644 --- a/Tests/NeronTests/TestClasses/TestView.swift +++ b/Tests/NeronTests/TestClasses/TestView.swift @@ -2,15 +2,14 @@ // Copyright © 2020 Jakub Kiermasz. All rights reserved. // - @testable import Neron final class TestView: View { // MARK: - Properties - let width: CGFloat = 200 - let height: CGFloat = 200 + let width: CGFloat + let height: CGFloat // MARK: - Getters @@ -26,7 +25,9 @@ final class TestView: View { // MARK: - Initialization - init() { + init(width: CGFloat = 200, height: CGFloat = 200) { + self.width = width + self.height = height super.init(frame: CGRect(x: 0, y: 0, width: width, height: height)) } diff --git a/Tests/NeronTests/ViewLayout/ViewLayout+Layout+Dimension+Tests.swift b/Tests/NeronTests/ViewLayout/ViewLayout+Layout+Dimension+Tests.swift index 6225fb7..c870b06 100644 --- a/Tests/NeronTests/ViewLayout/ViewLayout+Layout+Dimension+Tests.swift +++ b/Tests/NeronTests/ViewLayout/ViewLayout+Layout+Dimension+Tests.swift @@ -60,7 +60,6 @@ final class ViewLayout_Layout_Dimension_Tests: XCTestCase { func test_Height_EqualToSibling() { let view = TestView() - print(parent.frame) let constraint = view.layout .add(to: parent) .height.equalTo(parent, .height) @@ -73,30 +72,73 @@ final class ViewLayout_Layout_Dimension_Tests: XCTestCase { func test_Height_LessThanOrEqualToSibling() { let view = TestView() - print(parent.frame) let constraint = view.layout .add(to: parent) - .height.equalTo(parent, .height) + .height.lessThanOrEqualTo(parent, .height) .activate() .constraint parent.prepare() XCTAssertLessThanOrEqual(view.frame.height, 200, "Height should be 200") - XCTAssertEqual(constraint.relation, .equal, "Relation should be lessThanOrEqual") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") } func test_Height_GreaterThanOrEqualToSibling() { let view = TestView() - print(parent.frame) let constraint = view.layout .add(to: parent) - .height.equalTo(parent, .height) + .height.greaterThanOrEqualTo(parent, .height) .activate() .constraint parent.prepare() XCTAssertGreaterThanOrEqual(view.frame.height, 200, "Height should be 200") - XCTAssertEqual(constraint.relation, .equal, "Relation should be greaterThanOrEqual") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") } - + + func test_Height_EqualToLayoutGuide() { + let height: CGFloat = 150 + let parent = TestView(height: height) + let guide = parent.layoutGuide + let view = TestView() + let constraint = view.layout + .add(to: parent) + .height.equalTo(guide, .height) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(view.frame.height, height, "Height should be \(height)") + XCTAssertEqual(constraint.relation, .equal, "Relation should be equal") + } + + func test_Height_LessThanOrEqualToLayoutGuide() { + let height: CGFloat = 150 + let parent = TestView(height: height) + let guide = parent.layoutGuide + let view = TestView() + let constraint = view.layout + .add(to: parent) + .height.lessThanOrEqualTo(guide, .height) + .activate() + .constraint + parent.prepare() + XCTAssertLessThanOrEqual(view.frame.height, height, "Height should be \(height)") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") + } + + func test_Height_GreaterThanOrEqualToLayoutGuide() { + let height: CGFloat = 150 + let parent = TestView(height: height) + let guide = parent.layoutGuide + let view = TestView() + let constraint = view.layout + .add(to: parent) + .height.greaterThanOrEqualTo(guide, .height) + .activate() + .constraint + parent.prepare() + XCTAssertGreaterThanOrEqual(view.frame.height, height, "Height should be \(height)") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") + } + // MARK: - Width func test_Width_EqualToConstant() { @@ -137,7 +179,6 @@ final class ViewLayout_Layout_Dimension_Tests: XCTestCase { func test_Width_EqualToSibling() { let view = TestView() - print(parent.frame) let constraint = view.layout .add(to: parent) .width.equalTo(parent, .width) @@ -150,28 +191,71 @@ final class ViewLayout_Layout_Dimension_Tests: XCTestCase { func test_Width_LessThanOrEqualToSibling() { let view = TestView() - print(parent.frame) let constraint = view.layout .add(to: parent) - .width.equalTo(parent, .width) + .width.lessThanOrEqualTo(parent, .width) .activate() .constraint parent.prepare() XCTAssertLessThanOrEqual(view.frame.width, 200, "Width should be 200") - XCTAssertEqual(constraint.relation, .equal, "Relation should be lessThanOrEqual") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") } func test_Width_GreaterThanOrEqualToSibling() { let view = TestView() - print(parent.frame) let constraint = view.layout .add(to: parent) - .width.equalTo(parent, .width) + .width.greaterThanOrEqualTo(parent, .width) .activate() .constraint parent.prepare() XCTAssertGreaterThanOrEqual(view.frame.width, 200, "Width should be 200") - XCTAssertEqual(constraint.relation, .equal, "Relation should be greaterThanOrEqual") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") } - + + func test_Width_EqualToLayoutGuide() { + let width: CGFloat = 150 + let parent = TestView(width: width) + let guide = parent.layoutGuide + let view = TestView() + let constraint = view.layout + .add(to: parent) + .width.equalTo(guide, .width) + .activate() + .constraint + parent.prepare() + XCTAssertEqual(view.frame.width, width, "Width should be \(width)") + XCTAssertEqual(constraint.relation, .equal, "Relation should be equal") + } + + func test_Width_LessThanOrEqualToLayoutGuide() { + let width: CGFloat = 150 + let parent = TestView(width: width) + let guide = parent.layoutGuide + let view = TestView() + let constraint = view.layout + .add(to: parent) + .width.lessThanOrEqualTo(guide, .width) + .activate() + .constraint + parent.prepare() + XCTAssertLessThanOrEqual(view.frame.width, width, "Width should be \(width)") + XCTAssertEqual(constraint.relation, .lessThanOrEqual, "Relation should be lessThanOrEqual") + } + + func test_Width_GreaterThanOrEqualToLayoutGuide() { + let width: CGFloat = 150 + let parent = TestView(width: width) + let guide = parent.layoutGuide + let view = TestView() + let constraint = view.layout + .add(to: parent) + .width.greaterThanOrEqualTo(guide, .width) + .activate() + .constraint + parent.prepare() + XCTAssertGreaterThanOrEqual(view.frame.width, width, "Width should be \(width)") + XCTAssertEqual(constraint.relation, .greaterThanOrEqual, "Relation should be greaterThanOrEqual") + } + }