diff --git a/Example/FramezillaExample/ViewController.swift b/Example/FramezillaExample/ViewController.swift index 2a5ba16..5bb0977 100644 --- a/Example/FramezillaExample/ViewController.swift +++ b/Example/FramezillaExample/ViewController.swift @@ -11,98 +11,73 @@ import Framezilla class ViewController: UIViewController { + let container = UIView() + let content1 = UIView() let content2 = UIView() let content3 = UIView() let content4 = UIView() + let label1 = UILabel() + let label2 = UILabel() + let label3 = UILabel() + override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white + container.backgroundColor = .yellow + content1.backgroundColor = .red content2.backgroundColor = .black content3.backgroundColor = .green content4.backgroundColor = .gray + + label1.backgroundColor = .red + label2.backgroundColor = .green + label3.backgroundColor = .gray + + label1.numberOfLines = 0 + label2.numberOfLines = 0 + label3.numberOfLines = 0 + + label1.text = "Helloe Helloe Helloe Helloe Helloe Helloe Helloe Helloe Helloe Helloe Helloe" + label2.text = "Helloe Helloe Helloe Helloe Helloe" + label3.text = "Helloe" + + view.addSubview(container) } override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() -// let container = [content1, content2, content3, content4].container(in: view) { -// content1.configureFrame { maker in -// maker.centerX() -// maker.top() -// maker.size(width: 50, height: 50) -// } -// -// content2.configureFrame { maker in -// maker.top(to: content1.nui_bottom, inset: 5) -// maker.left() -// maker.size(width: 80, height: 80) -// } -// -// content3.configureFrame { maker in -// maker.top(to: content1.nui_bottom, inset: 15) -// maker.left(to: content2.nui_right, inset: 5) -// maker.size(width: 80, height: 80) -// } -// -// content4.configureFrame { maker in -// maker.top(to: content3.nui_bottom, inset: 5) -// maker.right() -// maker.size(width: 20, height: 20) -// } -// } - - - - let container = [content1, content2, content3].container(in: view) { + [content1, label1, label2, label3].configure(container: container, relation: .horizontal(left: 20, right: 20)) { content1.configureFrame { maker in - maker.right() - maker.centerY() - maker.size(width: 50, height: 50) + maker.top(inset: 10) + maker.size(width: 100, height: 60) + maker.centerX() } - content2.configureFrame { maker in - maker.right(to: content1.nui_left, inset: 5) - maker.centerY() - maker.size(width: 30, height: 140) + label1.configureFrame { maker in + maker.left().right().top(to: content1.nui_bottom, inset: 10) + maker.heightToFit() } - content3.configureFrame { maker in - maker.right(to: content2.nui_left, inset: 15) - maker.centerY() - maker.size(width: 80, height: 80) + label2.configureFrame { maker in + maker.left().right().top(to: label1.nui_bottom, inset: 10) + maker.heightToFit() } - } - -// let container = [content1, content2, content3].container(in: view) { -// content1.configureFrame { maker in -// maker.bottom() -// maker.centerX() -// maker.size(width: 50, height: 50) -// } -// -// content2.configureFrame { maker in -// maker.bottom(to: content1.nui_top, inset: 5) -// maker.centerX() -// maker.size(width: 30, height: 140) -// } -// -// content3.configureFrame { maker in -// maker.left() -// maker.bottom(to: content2.nui_top, inset: 15) -// maker.size(width: 10, height: 10) -// } -// } + label3.configureFrame { maker in + maker.left().right().top(to: label2.nui_bottom, inset: 20) + maker.heightToFit() + } + } - container.backgroundColor = .yellow container.configureFrame { maker in maker.centerX() - maker.top() + maker.bottom(inset: 20) } } } diff --git a/Framezilla.podspec b/Framezilla.podspec index 9f3ce09..35bd0d7 100644 --- a/Framezilla.podspec +++ b/Framezilla.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |spec| spec.name = "Framezilla" - spec.version = "2.7.0" + spec.version = "2.8.0" spec.summary = "Comfortable syntax for working with frames." spec.homepage = "https://github.com/Otbivnoe/Framezilla" diff --git a/Framezilla.xcodeproj/project.pbxproj b/Framezilla.xcodeproj/project.pbxproj index e25659b..70690be 100644 --- a/Framezilla.xcodeproj/project.pbxproj +++ b/Framezilla.xcodeproj/project.pbxproj @@ -14,7 +14,7 @@ 11FB41471D844F8F00700A40 /* MakerHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FB41421D844F8F00700A40 /* MakerHelper.swift */; }; 11FB41481D844F8F00700A40 /* UIView+Installer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FB41431D844F8F00700A40 /* UIView+Installer.swift */; }; 11FB41491D844F8F00700A40 /* UIView+Relations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11FB41441D844F8F00700A40 /* UIView+Relations.swift */; }; - 841192DD1FF205DC00AB255D /* ContainerInstallerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841192DC1FF205DC00AB255D /* ContainerInstallerTests.swift */; }; + 841192DD1FF205DC00AB255D /* ContainerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 841192DC1FF205DC00AB255D /* ContainerTests.swift */; }; 842BB7FC1F0638E9000D1CFF /* Parameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842BB7FB1F0638E9000D1CFF /* Parameters.swift */; }; 8442F93E1EC75A8500B72551 /* BaseTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442F9351EC75A8500B72551 /* BaseTest.swift */; }; 8442F9401EC75A8500B72551 /* MakerBothSideRelationsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8442F9381EC75A8500B72551 /* MakerBothSideRelationsTests.swift */; }; @@ -52,7 +52,7 @@ 11FB414A1D844FFA00700A40 /* Framezilla.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Framezilla.podspec; sourceTree = ""; }; 11FB414B1D844FFA00700A40 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 11FB414C1D844FFA00700A40 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; - 841192DC1FF205DC00AB255D /* ContainerInstallerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerInstallerTests.swift; sourceTree = ""; }; + 841192DC1FF205DC00AB255D /* ContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.swift; sourceTree = ""; }; 842BB7FB1F0638E9000D1CFF /* Parameters.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parameters.swift; sourceTree = ""; }; 8442F9351EC75A8500B72551 /* BaseTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTest.swift; sourceTree = ""; }; 8442F9361EC75A8500B72551 /* FramezillaTests-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FramezillaTests-Bridging-Header.h"; sourceTree = ""; }; @@ -140,7 +140,7 @@ 84EDCC231F9B3AB10091FAB9 /* MakerSafeAreaTests.swift */, 8442F93D1EC75A8500B72551 /* StateTests.swift */, 845108061EE2F5BC006DC1C8 /* ScrollViewTests.swift */, - 841192DC1FF205DC00AB255D /* ContainerInstallerTests.swift */, + 841192DC1FF205DC00AB255D /* ContainerTests.swift */, ); path = Tests; sourceTree = ""; @@ -276,7 +276,7 @@ files = ( 8442F9441EC75A8500B72551 /* MakerWidthHeightTests.swift in Sources */, 8442F9451EC75A8500B72551 /* StateTests.swift in Sources */, - 841192DD1FF205DC00AB255D /* ContainerInstallerTests.swift in Sources */, + 841192DD1FF205DC00AB255D /* ContainerTests.swift in Sources */, 8442F9411EC75A8500B72551 /* MakerCenterTests.swift in Sources */, 8442F9421EC75A8500B72551 /* MakerStackTests.swift in Sources */, 8442F9401EC75A8500B72551 /* MakerBothSideRelationsTests.swift in Sources */, diff --git a/README.md b/README.md index 40c2843..73eeed2 100644 --- a/README.md +++ b/README.md @@ -222,18 +222,31 @@ label.configureFrame { maker in ## Container -Use this method when you want to set `width` and `height` by wrapping all subviews. +Use this method when you want to calculate a `width` and `height` by wrapping all subviews. + +You can also specify a special container relation: + +```swift +public enum ContainerRelation { + case width(Number) + case height(Number) + case horizontal(left: Number, right: Number) + case vertical(top: Number, bottom: Number) +} +``` + +For instance, if you set a width for a container, only a dynamic height will be calculated. ### NOTE: **It atomatically adds all subviews to the container. Don't add subviews manually.** -**Also important to understand, that it's not correct to call 'left' and 'right' relations together by subview, because `container` sets width relatively width of subview and here is some ambiguous.** +**If you don't use a static width for instance, important to understand, that it's not correct to call `left` and `right` relations together by subviews, because `container` sets width relatively width of subviews and here is some ambiguous.** ![](img/container.png) ```swift -let container = [content1, content2, content3, content4].container(in: view) { +let container = [content1, content2, content3, content4].container(in: view, relation: /* if needed */) { content1.configureFrame { maker in maker.centerX() maker.top() @@ -265,6 +278,14 @@ container.configureFrame { maker in } ``` +If you have already configured container, then this method will be more convenient for you: + +```swift +[content1, label1, label2, label3].configure(container: container, relation: .horizontal(left: 20, right: 20)) { +// do configuration +} +``` + ## Cool things: Sometimes you want to configure a few views with the same size, for examlple. There is a convinience method: diff --git a/Sources/Maker.swift b/Sources/Maker.swift index 6cb0664..e58ea84 100644 --- a/Sources/Maker.swift +++ b/Sources/Maker.swift @@ -384,6 +384,14 @@ public final class Maker { var minY: CGFloat = 0 for subview in view.subviews { + if subview.frame.origin.x < 0 { + subview.frame.origin.x = 0 + } + + if subview.frame.origin.y < 0 { + subview.frame.origin.y = 0 + } + if subview.frame.origin.x < minX { minX = subview.frame.origin.x } @@ -662,7 +670,7 @@ public final class Maker { /// Use this method when you want to join right side of current view with some horizontal side of another view. /// /// - note: You can not use this method with other relations except for `nui_left`, `nui_centerX` and `nui_right`. - // + /// /// - parameter relationView: The view on which you set right relation. /// - parameter inset: The inset for additional space between views. Default value: 0. /// diff --git a/Sources/UIView+Installer.swift b/Sources/UIView+Installer.swift index 7e0c9c1..383e90a 100644 --- a/Sources/UIView+Installer.swift +++ b/Sources/UIView+Installer.swift @@ -115,22 +115,85 @@ public extension Sequence where Iterator.Element: UIView { } } +public enum ContainerRelation { + case width(Number) + case height(Number) + case horizontal(left: Number, right: Number) + case vertical(top: Number, bottom: Number) +} + public extension Collection where Iterator.Element: UIView, Self.Index == Int, Self.IndexDistance == Int { - /// Creates сontainer view and configures all subview within this container. + /// Configures all subview within a passed container. /// - /// Use this method when you want to set `width` and `height` by wrapping all subviews. + /// Use this method when you want to calculate width and height by wrapping all subviews. Or use static parameters. /// - /// - note: It atomatically adds all subviews to the container. Don't add subviews manually. - /// - note: Also important to understand, that it's not correct to call 'left' and 'right' relations together by subview, because - /// `container` sets width relatively width of subview and here is some ambiguous. + /// - note: It automatically adds all subviews to the container. Don't add subviews manually. + /// - note: If you don't use a static width for instance, important to understand, that it's not correct to call 'left' and 'right' relations together by subviews, + /// because `container` sets width relatively width of subviews and here is some ambiguous. /// - /// - parameter view: The view where a container will be added. - /// - parameter installerBlock: The installer block within which you should configure frames for all subviews. + /// - parameter view: The view where a container will be added. + /// - parameter relation: The relation of `ContainerRelation` type. + /// - `width`: The width of a container. If you specify a width only a dynamic height will be calculated. + /// - `height`: The height of a container. If you specify a height only a dynamic width will be calculated. + /// - `horizontal(left, right)`: The left and right insets of a container. If you specify these parameters only a dynamic height will be calculated. + /// - `vertical(top, bottom)`: The top and bototm insets of a container. If you specify these parameters only a dynamic width will be calculated. + /// - parameter installerBlock: The installer block within which you should configure frames for all subviews. + + public func configure(container: UIView, relation: ContainerRelation? = nil, installerBlock: () -> Void) { + container.frame = .zero + + if let relation = relation { + switch relation { + case let .width(width): container.frame.size.width = width.value + case let .height(height): container.frame.size.height = height.value + case let .horizontal(lInset, rInset): + container.configureFrame { maker in + maker.left(inset: lInset).right(inset: rInset) + } + let width = container.frame.width + container.frame = .zero + container.frame.size.width = width + case let .vertical(tInset, bInset): + container.configureFrame { maker in + maker.top(inset: tInset).bottom(inset: bInset) + } + let height = container.frame.height + container.frame = .zero + container.frame.size.height = height + } + } + + for subview in self { + container.addSubview(subview) + } + + installerBlock() + container.configureFrame { maker in + maker.container() + } + installerBlock() + } + + /// Creates a сontainer view and configures all subview within this container. + /// + /// Use this method when you want to calculate `width` and `height` by wrapping all subviews. Or use static parameters. + /// + /// - note: It automatically adds all subviews to the container. Don't add subviews manually. A generated container is automatically added to a `view` as well. + /// - note: If you don't use a static width for instance, important to understand, that it's not correct to call 'left' and 'right' relations together by subviews, + /// because `container` sets width relatively width of subviews and here is some ambiguous. + /// + /// - parameter view: The view where a container will be added. + /// - parameter relation: The relation of `ContainerRelation` type. + /// - `width`: The width of a container. If you specify a width only a dynamic height will be calculated. + /// - `height`: The height of a container. If you specify a height only a dynamic width will be calculated. + /// - `horizontal(left, right)`: The left and right insets of a container. If you specify these parameters only a dynamic height will be calculated. + /// - `vertical(top, bottom)`: The top and bototm insets of a container. If you specify these parameters only a dynamic width will be calculated. + /// - parameter installerBlock: The installer block within which you should configure frames for all subviews. /// /// - returns: Container view. - public func container(in view: UIView, installerBlock: () -> Void) -> UIView { + public func container(in view: UIView, relation: ContainerRelation? = nil, installerBlock: () -> Void) -> UIView { let container: UIView if let superView = self.first?.superview { container = superView @@ -138,16 +201,9 @@ public extension Collection where Iterator.Element: UIView, Self.Index == Int, S else { container = UIView() } - for view in self { - container.addSubview(view) - } + view.addSubview(container) - - installerBlock() - container.configureFrame { maker in - maker.container() - } - installerBlock() + configure(container: container, relation: relation, installerBlock: installerBlock) return container } } diff --git a/Tests/ContainerInstallerTests.swift b/Tests/ContainerInstallerTests.swift deleted file mode 100644 index cbbbcc0..0000000 --- a/Tests/ContainerInstallerTests.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// ContainerInstallerTests.swift -// FramezillaTests -// -// Created by Nikita Ermolenko on 26/12/2017. -// - -import XCTest - -class ContainerInstallerTests: BaseTest { - - func testContainerConfigurationFromTopToBottom() { - let content1 = UIView() - let content2 = UIView() - let content3 = UIView() - let content4 = UIView() - - _ = [content1, content2, content3, content4].container(in: mainView) { - content1.configureFrame { maker in - maker.centerX() - maker.top() - maker.size(width: 50, height: 50) - } - - content2.configureFrame { maker in - maker.top(to: content1.nui_bottom, inset: 5) - maker.left() - maker.size(width: 80, height: 80) - } - - content3.configureFrame { maker in - maker.top(to: content1.nui_bottom, inset: 15) - maker.left(to: content2.nui_right, inset: 5) - maker.size(width: 80, height: 80) - } - - content4.configureFrame { maker in - maker.top(to: content3.nui_bottom, inset: 5) - maker.right() - maker.size(width: 20, height: 20) - } - } - - XCTAssertEqual(content1.frame, CGRect(x: 70, y: 0, width: 50, height: 50)) - XCTAssertEqual(content2.frame, CGRect(x: 0, y: 55, width: 80, height: 80)) - XCTAssertEqual(content3.frame, CGRect(x: 85, y: 65, width: 80, height: 80)) - XCTAssertEqual(content4.frame, CGRect(x: 170, y: 150, width: 20, height: 20)) - } - - func testContainerConfigurationFromRightToLeft() { - let content1 = UIView() - let content2 = UIView() - let content3 = UIView() - - _ = [content1, content2, content3].container(in: mainView) { - content1.configureFrame { maker in - maker.right() - maker.centerY() - maker.size(width: 50, height: 50) - } - - content2.configureFrame { maker in - maker.right(to: content1.nui_left, inset: 5) - maker.centerY() - maker.size(width: 30, height: 140) - } - - content3.configureFrame { maker in - maker.right(to: content2.nui_left, inset: 15) - maker.centerY() - maker.size(width: 80, height: 80) - } - } - - XCTAssertEqual(content1.frame, CGRect(x: 130, y: 45, width: 50, height: 50)) - XCTAssertEqual(content2.frame, CGRect(x: 95, y: 0, width: 30, height: 140)) - XCTAssertEqual(content3.frame, CGRect(x: 0, y: 30, width: 80, height: 80)) - } -} diff --git a/Tests/ContainerTests.swift b/Tests/ContainerTests.swift new file mode 100644 index 0000000..0916a2d --- /dev/null +++ b/Tests/ContainerTests.swift @@ -0,0 +1,275 @@ +// +// ContainerTests.swift +// FramezillaTests +// +// Created by Nikita Ermolenko on 26/12/2017. +// + +import XCTest +import Framezilla + +class ContainerTests: BaseTest { + + func testContainerConfigurationFromTopToBottom() { + let content1 = UIView() + let content2 = UIView() + let content3 = UIView() + let content4 = UIView() + + let container = [content1, content2, content3, content4].container(in: mainView) { + content1.configureFrame { maker in + maker.centerX() + maker.top() + maker.size(width: 50, height: 50) + } + + content2.configureFrame { maker in + maker.top(to: content1.nui_bottom, inset: 5) + maker.left() + maker.size(width: 80, height: 80) + } + + content3.configureFrame { maker in + maker.top(to: content1.nui_bottom, inset: 15) + maker.left(to: content2.nui_right, inset: 5) + maker.size(width: 80, height: 80) + } + + content4.configureFrame { maker in + maker.top(to: content3.nui_bottom, inset: 5) + maker.right() + maker.size(width: 20, height: 20) + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 165, height: 170)) + XCTAssertEqual(content1.frame, CGRect(x: 57.5, y: 0, width: 50, height: 50)) + XCTAssertEqual(content2.frame, CGRect(x: 0, y: 55, width: 80, height: 80)) + XCTAssertEqual(content3.frame, CGRect(x: 85, y: 65, width: 80, height: 80)) + XCTAssertEqual(content4.frame, CGRect(x: 145, y: 150, width: 20, height: 20)) + } + + func testContainerConfigurationFromLeftToRight() { + let content1 = UIView() + let content2 = UIView() + let content3 = UIView() + + let container = [content1, content2, content3].container(in: mainView) { + content1.configureFrame { maker in + maker.left() + maker.centerY() + maker.size(width: 50, height: 50) + } + + content2.configureFrame { maker in + maker.left(to: content1.nui_right, inset: 5) + maker.centerY() + maker.size(width: 30, height: 140) + } + + content3.configureFrame { maker in + maker.left(to: content2.nui_right, inset: 15) + maker.centerY() + maker.size(width: 80, height: 80) + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 180, height: 140)) + XCTAssertEqual(content1.frame, CGRect(x: 0, y: 45, width: 50, height: 50)) + XCTAssertEqual(content2.frame, CGRect(x: 55, y: 0, width: 30, height: 140)) + XCTAssertEqual(content3.frame, CGRect(x: 100, y: 30, width: 80, height: 80)) + } + + func testContainerConfigurationWithCenterYRelation() { + let content1 = UIView() + let content2 = UIView() + + let container = [content1, content2].container(in: mainView) { + content1.configureFrame { maker in + maker.top(inset: 10) + maker.centerX() + maker.size(width: 180, height: 50) + } + + content2.configureFrame { maker in + maker.top(to: content1.nui_bottom, inset: 10) + maker.left() + maker.size(width: 250, height: 200) + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 250, height: 270)) + XCTAssertEqual(content1.frame, CGRect(x: 35, y: 10, width: 180, height: 50)) + XCTAssertEqual(content2.frame, CGRect(x: 0, y: 70, width: 250, height: 200)) + } + + func testContainerConfigurationWithCenterXRelation() { + let content1 = UIView() + let content2 = UIView() + + let container = [content1, content2].container(in: mainView) { + content2.configureFrame { maker in + maker.top().left(inset: 10) + maker.size(width: 200, height: 250) + } + + content1.configureFrame { maker in + maker.left(to: content2.nui_right, inset: 10) + maker.centerY() + maker.size(width: 50, height: 180) + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 270, height: 250)) + XCTAssertEqual(content1.frame, CGRect(x: 220, y: 35, width: 50, height: 180)) + XCTAssertEqual(content2.frame, CGRect(x: 10, y: 0, width: 200, height: 250)) + } + + func testContainerConfigurationWithStaticWidth() { + let content1 = UIView() + let content2 = UIView() + let content3 = UIView() + let content4 = UIView() + + let container = [content1, content2, content3, content4].container(in: mainView, relation: .width(200)) { + content1.configureFrame { maker in + maker.top(inset: 10) + maker.size(width: 100, height: 60) + maker.centerX() + } + + content2.configureFrame { maker in + maker.left().right().top(to: content1.nui_bottom, inset: 10) + maker.height(50) + } + + content3.configureFrame { maker in + maker.left().right().top(to: content2.nui_bottom, inset: 10) + maker.height(70) + } + + content4.configureFrame { maker in + maker.top(to: content3.nui_bottom, inset: 20) + maker.size(width: 30, height: 30) + maker.centerX() + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 200, height: 260)) + XCTAssertEqual(content1.frame, CGRect(x: 50, y: 10, width: 100, height: 60)) + XCTAssertEqual(content2.frame, CGRect(x: 0, y: 80, width: 200, height: 50)) + XCTAssertEqual(content3.frame, CGRect(x: 0, y: 140, width: 200, height: 70)) + XCTAssertEqual(content4.frame, CGRect(x: 85, y: 230, width: 30, height: 30)) + } + + func testContainerConfigurationWithStaticHeight() { + let content1 = UIView() + let content2 = UIView() + let content3 = UIView() + let content4 = UIView() + + let container = [content1, content2, content3, content4].container(in: mainView, relation: .height(200)) { + content1.configureFrame { maker in + maker.left(inset: 10) + maker.size(width: 60, height: 100) + maker.centerY() + } + + content2.configureFrame { maker in + maker.top().bottom().left(to: content1.nui_right, inset: 10) + maker.width(50) + } + + content3.configureFrame { maker in + maker.top().bottom().left(to: content2.nui_right, inset: 10) + maker.width(70) + } + + content4.configureFrame { maker in + maker.left(to: content3.nui_right, inset: 20) + maker.size(width: 30, height: 30) + maker.centerY() + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 260, height: 200)) + XCTAssertEqual(content1.frame, CGRect(x: 10, y: 50, width: 60, height: 100)) + XCTAssertEqual(content2.frame, CGRect(x: 80, y: 0, width: 50, height: 200)) + XCTAssertEqual(content3.frame, CGRect(x: 140, y: 0, width: 70, height: 200)) + XCTAssertEqual(content4.frame, CGRect(x: 230, y: 85, width: 30, height: 30)) + } + + func testContainerConfigurationWithLeftAndRightRelations() { + let content1 = UIView() + let content2 = UIView() + let content3 = UIView() + let content4 = UIView() + + let container = [content1, content2, content3, content4].container(in: mainView, relation: .horizontal(left: 150, right: 150)) { + content1.configureFrame { maker in + maker.top(inset: 10) + maker.size(width: 100, height: 60) + maker.centerX() + } + + content2.configureFrame { maker in + maker.left().right().top(to: content1.nui_bottom, inset: 10) + maker.height(50) + } + + content3.configureFrame { maker in + maker.left().right().top(to: content2.nui_bottom, inset: 10) + maker.height(70) + } + + content4.configureFrame { maker in + maker.top(to: content3.nui_bottom, inset: 20) + maker.size(width: 30, height: 30) + maker.centerX() + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 200, height: 260)) + XCTAssertEqual(content1.frame, CGRect(x: 50, y: 10, width: 100, height: 60)) + XCTAssertEqual(content2.frame, CGRect(x: 0, y: 80, width: 200, height: 50)) + XCTAssertEqual(content3.frame, CGRect(x: 0, y: 140, width: 200, height: 70)) + XCTAssertEqual(content4.frame, CGRect(x: 85, y: 230, width: 30, height: 30)) + } + + func testContainerConfigurationWithTopAndBottomRelations() { + let content1 = UIView() + let content2 = UIView() + let content3 = UIView() + let content4 = UIView() + + let container = [content1, content2, content3, content4].container(in: mainView, relation: .vertical(top: 150, bottom: 150)) { + content1.configureFrame { maker in + maker.left(inset: 10) + maker.size(width: 60, height: 100) + maker.centerY() + } + + content2.configureFrame { maker in + maker.top().bottom().left(to: content1.nui_right, inset: 10) + maker.width(50) + } + + content3.configureFrame { maker in + maker.top().bottom().left(to: content2.nui_right, inset: 10) + maker.width(70) + } + + content4.configureFrame { maker in + maker.left(to: content3.nui_right, inset: 20) + maker.size(width: 30, height: 30) + maker.centerY() + } + } + + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 260, height: 200)) + XCTAssertEqual(content1.frame, CGRect(x: 10, y: 50, width: 60, height: 100)) + XCTAssertEqual(content2.frame, CGRect(x: 80, y: 0, width: 50, height: 200)) + XCTAssertEqual(content3.frame, CGRect(x: 140, y: 0, width: 70, height: 200)) + XCTAssertEqual(content4.frame, CGRect(x: 230, y: 85, width: 30, height: 30)) + } +}