From 47353b7b15710cde21c1b226b85df9e403bf3694 Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 24 Apr 2019 15:19:11 +0600 Subject: [PATCH 1/8] Switch to view-based safe area relations --- Sources/Maker.swift | 4 +++ Sources/MakerHelper.swift | 45 ++++++++++++++++++++++++++++------ Sources/UIView+Relations.swift | 29 +++++++++++++++++++++- 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/Sources/Maker.swift b/Sources/Maker.swift index 79dcb17..8cedef5 100644 --- a/Sources/Maker.swift +++ b/Sources/Maker.swift @@ -265,6 +265,7 @@ public final class Maker { /// /// - returns: `Maker` instance for chaining relations. + @available(*, deprecated, message: "Use `left(to: view.nui_safeArea.left, inset: ...)` instead") @discardableResult public func left(to safeArea: SafeArea, inset: Number = 0.0) -> Maker { if #available(iOS 11.0, *) { guard let superview = view.superview else { @@ -329,6 +330,7 @@ public final class Maker { /// /// - returns: `Maker` instance for chaining relations. + @available(*, deprecated, message: "Use `top(to: view.nui_safeArea.top, inset: ...)` instead") @discardableResult public func top(to safeArea: SafeArea, inset: Number = 0.0) -> Maker { if #available(iOS 11.0, *) { guard let superview = view.superview else { @@ -592,6 +594,7 @@ public final class Maker { /// /// - returns: `Maker` instance for chaining relations. + @available(*, deprecated, message: "Use `bottom(to: view.nui_safeArea.bottom, inset: ...)` instead") @discardableResult public func bottom(to safeArea: SafeArea, inset: Number = 0.0) -> Maker { if #available(iOS 11.0, *) { guard let superview = view.superview else { @@ -662,6 +665,7 @@ public final class Maker { /// /// - returns: `Maker` instance for chaining relations. + @available(*, deprecated, message: "Use `right(to: view.nui_safeArea.right, inset: ...)` instead") @discardableResult public func right(to safeArea: SafeArea, inset: Number = 0.0) -> Maker { if #available(iOS 11.0, *) { guard let superview = view.superview else { diff --git a/Sources/MakerHelper.swift b/Sources/MakerHelper.swift index 3c08df2..8b96394 100644 --- a/Sources/MakerHelper.swift +++ b/Sources/MakerHelper.swift @@ -45,13 +45,44 @@ extension Maker { } switch type { - case .top: return convertedRect.minY - case .bottom: return convertedRect.maxY - case .centerY: return view.contains(self.view) ? convertedRect.height / 2 : convertedRect.midY - case .centerX: return view.contains(self.view) ? convertedRect.width / 2 : convertedRect.midX - case .right: return convertedRect.maxX - case .left: return convertedRect.minX - default: return 0 + case .top: + return convertedRect.minY + case .bottom: + return convertedRect.maxY + case .centerY: + return view.contains(self.view) ? convertedRect.height / 2 : convertedRect.midY + case .centerX: + return view.contains(self.view) ? convertedRect.width / 2 : convertedRect.midX + case .right: + return convertedRect.maxX + case .left: + return convertedRect.minX + case .safeArea(.top): + if #available(iOS 11.0, *) { + return convertedRect.minY + view.safeAreaInsets.top + } + + return convertedRect.minY + case .safeArea(.left): + if #available(iOS 11.0, *) { + return convertedRect.minX + view.safeAreaInsets.left + } + + return convertedRect.minX + case .safeArea(.right): + if #available(iOS 11.0, *) { + return convertedRect.maxX - view.safeAreaInsets.right + } + + return convertedRect.maxX + case .safeArea(.bottom): + if #available(iOS 11.0, *) { + return convertedRect.maxY - view.safeAreaInsets.bottom + } + + return convertedRect.maxY + default: + return 0 } } diff --git a/Sources/UIView+Relations.swift b/Sources/UIView+Relations.swift index f78354f..6aacfac 100644 --- a/Sources/UIView+Relations.swift +++ b/Sources/UIView+Relations.swift @@ -14,7 +14,7 @@ public protocol HorizontalRelation {} public protocol VerticalRelation {} -/// Phantom type for `nui_height`, `nui_widht` relations. +/// Phantom type for `nui_height`, `nui_width` relations. public protocol SizeRelation {} @@ -29,6 +29,13 @@ public final class RelationView { } } +enum SafeAreaType { + case top + case left + case right + case bottom +} + enum RelationType { case bottom case top @@ -40,6 +47,20 @@ enum RelationType { case heightTo case centerX case centerY + case safeArea(SafeAreaType) +} + +public struct SafeAreaRelationCollection { + unowned var view: UIView + + lazy var top = RelationView(view: view, relation: .safeArea(.top)) + lazy var left = RelationView(view: view, relation: .safeArea(.left)) + lazy var right = RelationView(view: view, relation: .safeArea(.right)) + lazy var bottom = RelationView(view: view, relation: .safeArea(.bottom)) + + init(view: UIView) { + self.view = view + } } public extension UIView { @@ -91,4 +112,10 @@ public extension UIView { public var nui_centerY: RelationView { return RelationView(view: self, relation: .centerY) } + + /// Safe area + + public var nui_safeArea: SafeAreaRelationCollection { + return SafeAreaRelationCollection(view: self) + } } From 422ab9cf341bb5e3719fa3e1617d0b2a11ee7008 Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 24 Apr 2019 15:25:09 +0600 Subject: [PATCH 2/8] Code cleanup --- Sources/Array+Stack.swift | 16 +-- Sources/Maker+Configurations.swift | 8 +- Sources/Maker+Unavailable.swift | 8 +- Sources/Maker.swift | 165 +++++++++++++++-------------- Sources/MakerHelper.swift | 6 +- Sources/Parameters.swift | 4 +- Sources/UIView+Installer.swift | 66 +++++++----- Sources/UIView+Relations.swift | 60 +++++------ 8 files changed, 171 insertions(+), 162 deletions(-) diff --git a/Sources/Array+Stack.swift b/Sources/Array+Stack.swift index f953b06..0051e1a 100644 --- a/Sources/Array+Stack.swift +++ b/Sources/Array+Stack.swift @@ -11,8 +11,8 @@ public enum StackAxis: Int { case vertical } -public extension Collection where Iterator.Element: UIView, Self.Index == Int, Self.IndexDistance == Int { - +public extension Collection where Iterator.Element: UIView, Self.Index == Int { + /// Arranges views in the order of list along a vertical or horizontal axis, with spacing property. /// /// - note: You have to change the `nx_state` of the container, not the arranged subviews. @@ -20,8 +20,8 @@ public extension Collection where Iterator.Element: UIView, Self.Index == Int, S /// - parameter axis: A stack with a horizontal axis is a row of arranged subviews, and a stack with a vertical axis is a column of arranged subviews. /// - parameter spacing: Spacing between arranged subviews. /// - parameter state: The state for which you configure frame. - - public func stack(axis: StackAxis, spacing: Number = 0.0, state: AnyHashable = DEFAULT_STATE) { + + func stack(axis: StackAxis, spacing: Number = 0.0, state: AnyHashable = DEFAULT_STATE) { for view in self { guard view.superview != nil else { assertionFailure("Can not configure stack relation without superview.") @@ -33,14 +33,14 @@ public extension Collection where Iterator.Element: UIView, Self.Index == Int, S for view in self where view.superview != superview { assertionFailure("All views should have the same superview.") } - + guard superview.nx_state == state else { return } - + let count = CGFloat(self.count) var prevView = self[0] - + switch axis { case .horizontal: let width = (superview.bounds.width - (count - 1) * spacing.value) / count @@ -74,7 +74,7 @@ public extension Collection where Iterator.Element: UIView, Self.Index == Int, S } prevView = view } - + } } } diff --git a/Sources/Maker+Configurations.swift b/Sources/Maker+Configurations.swift index 178e488..f33f61a 100644 --- a/Sources/Maker+Configurations.swift +++ b/Sources/Maker+Configurations.swift @@ -36,18 +36,18 @@ public postfix func >> (maker: Maker) { public typealias InstallerBlock = (Maker) -> Void extension Maker { - + class func configure(view: UIView, for state: AnyHashable, installerBlock: InstallerBlock) { if view.nx_state == state { let maker = Maker(view: view) - + maker.newRect = view.frame installerBlock(maker) - + maker.configureFrame() } } - + fileprivate func configureFrame() { handlers.sorted { $0.priority.rawValue <= $1.priority.rawValue diff --git a/Sources/Maker+Unavailable.swift b/Sources/Maker+Unavailable.swift index 6e82057..3036fa4 100644 --- a/Sources/Maker+Unavailable.swift +++ b/Sources/Maker+Unavailable.swift @@ -8,20 +8,20 @@ import Foundation extension Maker { - + /// Calculates the width that best fits the specified size. /// /// - returns: `Maker` instance for chaining relations. - + @available(*, unavailable, renamed: "widthThatFits(maxWidth:)") @discardableResult public func widthThatFits(width: Number) -> Maker { return self } - + /// Calculates the height that best fits the specified size. /// /// - returns: `Maker` instance for chaining relations. - + @available(*, unavailable, renamed: "heightThatFits(maxHeight:)") @discardableResult public func heightThatFits(height: Number) -> Maker { return self diff --git a/Sources/Maker.swift b/Sources/Maker.swift index 8cedef5..595a33c 100644 --- a/Sources/Maker.swift +++ b/Sources/Maker.swift @@ -20,41 +20,42 @@ enum HandlerPriority: Int { } public struct SafeArea {} +@available(*, deprecated, message: "Use `view.safeArea.` instead") public var nui_safeArea: SafeArea { return SafeArea() } public final class Maker { - + typealias HandlerType = () -> Void unowned let view: UIView - + var handlers = ContiguousArray<(priority: HandlerPriority, handler: HandlerType)>() var newRect: CGRect private var widthParameter: ValueParameter? private var widthToParameter: SideParameter? - + private var heightParameter: ValueParameter? private var heightToParameter: SideParameter? - + private var leftParameter: SideParameter? private var topParameter: SideParameter? private var bottomParameter: SideParameter? private var rightParameter: SideParameter? - + init(view: UIView) { self.view = view self.newRect = view.frame } - + // MARK: Additions - + /// Optional semantic property for improvements readability. /// /// - returns: `Maker` instance for chaining relations. - + public var and: Maker { return self } @@ -65,19 +66,19 @@ public final class Maker { /// - parameter insets: The insets for setting relations with `view`. Default value: `UIEdgeInsets.zero`. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func equal(to view: UIView, insets: UIEdgeInsets = .zero) -> Maker { let topView = RelationView(view: view, relation: .top) let leftView = RelationView(view: view, relation: .left) let bottomView = RelationView(view: view, relation: .bottom) let rightView = RelationView(view: view, relation: .right) - + return top(to: topView, inset: insets.top) .left(to: leftView, inset: insets.left) .bottom(to: bottomView, inset: insets.bottom) .right(to: rightView, inset: insets.right) } - + /// Creates edge relations. /// /// It's useful method for configure some side relations in short form. @@ -95,23 +96,23 @@ public final class Maker { /// - parameter right: The right inset relation relatively superview. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func edges(top: Number? = nil, left: Number? = nil, bottom: Number? = nil, right: Number? = nil) -> Maker { return apply(self.top, top).apply(self.left, left).apply(self.bottom, bottom).apply(self.right, right) } - + private func apply(_ f: ((Number) -> Maker), _ inset: Number?) -> Maker { return (inset != nil) ? f(inset!) : self } - + // MARK: High priority - + /// Installs constant width for current view. /// /// - parameter width: The width for view. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func width(_ width: Number) -> Maker { let handler = { [unowned self] in self.newRect.setValue(width.value, for: .width) @@ -120,8 +121,8 @@ public final class Maker { widthParameter = ValueParameter(value: width.value) return self } - - /// Creates width relation relatively another view = Aspect ration. + + /// Creates width relation relatively another view = Aspect ratio. /// /// Use this method when you want that your view's width equals to another view's height with some multiplier, for example. /// @@ -135,7 +136,7 @@ public final class Maker { @discardableResult public func width(to relationView: RelationView, multiplier: Number = 1.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in if view != self.view { let width = self.relationSize(view: view, for: relationType) * multiplier.value @@ -156,7 +157,7 @@ public final class Maker { let topViewY = self.convertedValue(for: topParameter.relationType, with: topParameter.view) + topParameter.value let bottomViewY = self.convertedValue(for: bottomParameter.relationType, with: bottomParameter.view) - bottomParameter.value - + self.newRect.setValue((bottomViewY - topViewY) * multiplier.value, for: .width) } } @@ -164,9 +165,9 @@ public final class Maker { handlers.append((.high, handler)) widthToParameter = SideParameter(view: view, value: multiplier.value, relationType: relationType) return self - + } - + /// Installs constant height for current view. /// /// - parameter height: The height for view. @@ -181,8 +182,8 @@ public final class Maker { heightParameter = ValueParameter(value: height.value) return self } - - /// Creates height relation relatively another view = Aspect ration. + + /// Creates height relation relatively another view = Aspect ratio. /// /// Use this method when you want that your view's height equals to another view's width with some multiplier, for example. /// @@ -192,11 +193,11 @@ public final class Maker { /// - parameter multiplier: The multiplier for views relation. Default multiplier value: 1. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func height(to relationView: RelationView, multiplier: Number = 1.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in if view != self.view { let height = self.relationSize(view: view, for: relationType) * multiplier.value @@ -217,7 +218,7 @@ public final class Maker { let leftViewX = self.convertedValue(for: leftParameter.relationType, with: leftParameter.view) + leftParameter.value let rightViewX = self.convertedValue(for: rightParameter.relationType, with: rightParameter.view) - rightParameter.value - + self.newRect.setValue((rightViewX - leftViewX) * multiplier.value, for: .height) } } @@ -226,14 +227,14 @@ public final class Maker { heightToParameter = SideParameter(view: view, value: multiplier.value, relationType: relationType) return self } - + /// Installs constant width and height at the same time. /// /// - parameter width: The width for view. /// - parameter height: The height for view. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func size(width: Number, height: Number) -> Maker { return self.width(width).height(height) } @@ -245,7 +246,7 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func left(inset: Number = 0.0) -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure left relation to superview without superview.") @@ -289,7 +290,7 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func left(to relationView: RelationView, inset: Number = 0.0) -> Maker { let view = relationView.view let relationType = relationView.relationType @@ -302,7 +303,7 @@ public final class Maker { leftParameter = SideParameter(view: view, value: inset.value, relationType: relationType) return self } - + /// Creates top relation to superview. /// /// Use this method when you want to join top side of current view with top side of superview. @@ -310,7 +311,7 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func top(inset: Number = 0.0) -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure a top relation to superview without superview.") @@ -354,11 +355,11 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func top(to relationView: RelationView, inset: Number = 0.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in let y = self.convertedValue(for: relationType, with: view) + inset.value self.newRect.setValue(y, for: .top) @@ -388,22 +389,22 @@ public final class Maker { @discardableResult public func container() -> Maker { return _container() } - + @discardableResult func _container() -> Maker { var frame = CGRect.zero - + var minX: CGFloat = 0 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 } @@ -411,14 +412,14 @@ public final class Maker { minY = subview.frame.origin.y } } - + for subview in view.subviews { subview.frame.origin.x -= minX subview.frame.origin.y -= minY - + frame = frame.union(subview.frame) } - + setHighPriorityValue(frame.width, for: .width) setHighPriorityValue(frame.height, for: .height) return self @@ -427,7 +428,7 @@ public final class Maker { /// Resizes the current view so it just encloses its subviews. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func sizeToFit() -> Maker { view.sizeToFit() setHighPriorityValue(view.bounds.width, for: .width) @@ -456,7 +457,7 @@ public final class Maker { /// Resizes and moves the receiver view so it just encloses its subviews only for height. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func heightToFit() -> Maker { return heightThatFits(maxHeight: CGFloat.greatestFiniteMagnitude) } @@ -495,7 +496,7 @@ public final class Maker { /// Resizes and moves the receiver view so it just encloses its subviews only for width. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func widthToFit() -> Maker { return widthThatFits(maxWidth: CGFloat.greatestFiniteMagnitude) } @@ -533,30 +534,30 @@ public final class Maker { } // MARK: Middle priority - + /// Creates margin relation for superview. /// /// - parameter inset: The inset for setting top, left, bottom and right relations for superview. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func margin(_ inset: Number) -> Maker { let inset = inset.value return edges(insets: UIEdgeInsets(top: inset, left: inset, bottom: inset, right: inset)) } - + /// Creates edge relations for superview. /// /// - parameter insets: The insets for setting relations for superview. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func edges(insets: UIEdgeInsets) -> Maker { guard let superview = view.superview else { assertionFailure("Can not create edge relations without superview.") return self } - + let handler = { [unowned self, unowned superview] in let width = superview.bounds.width - (insets.left + insets.right) let height = superview.bounds.height - (insets.top + insets.bottom) @@ -566,7 +567,7 @@ public final class Maker { handlers.append((.middle, handler)) return self } - + /// Creates bottom relation to superview. /// /// Use this method when you want to join bottom side of current view with bottom side of superview. @@ -574,7 +575,7 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func bottom(inset: Number = 0.0) -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure a bottom relation to superview without superview.") @@ -607,7 +608,7 @@ public final class Maker { return bottom(inset: inset) } } - + /// Creates bottom relation. /// /// Use this method when you want to join bottom side of current view with some vertical side of another view. @@ -618,11 +619,11 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func bottom(to relationView: RelationView, inset: Number = 0.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in if self.topParameter != nil { let height = fabs(self.newRect.minY - self.convertedValue(for: relationType, with: view)) - inset.value @@ -637,7 +638,7 @@ public final class Maker { bottomParameter = SideParameter(view: view, value: inset.value, relationType: relationType) return self } - + /// Creates right relation to superview. /// /// Use this method when you want to join right side of current view with right side of superview. @@ -645,7 +646,7 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func right(inset: Number = 0.0) -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure a right relation to superview without superview.") @@ -689,11 +690,11 @@ public final class Maker { /// - parameter inset: The inset for additional space between views. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func right(to relationView: RelationView, inset: Number = 0.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in if self.leftParameter != nil { let width = fabs(self.newRect.minX - self.convertedValue(for: relationType, with: view)) - inset.value @@ -708,7 +709,7 @@ public final class Maker { rightParameter = SideParameter(view: view, value: inset.value, relationType: relationType) return self } - + // MARK: Low priority /// Set up the corner radius value. @@ -745,7 +746,7 @@ public final class Maker { /// Use this method when you want to center view by both axis relativity superview. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func center() -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure a center relation to superview without superview.") @@ -753,7 +754,7 @@ public final class Maker { } return center(to: superview) } - + /// Creates center relation. /// /// Use this method when you want to center view by both axis relativity another view. @@ -761,12 +762,12 @@ public final class Maker { /// - parameter view: The view on which you set center relation. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func center(to view: UIView) -> Maker { return centerX(to: RelationView(view: view, relation: .centerX)) .centerY(to: RelationView(view: view, relation: .centerY)) } - + /// Creates centerY relation. /// /// Use this method when you want to join centerY of current view with centerY of superview. @@ -774,7 +775,7 @@ public final class Maker { /// - parameter offset: Additional offset for centerY point. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func centerY(offset: Number = 0.0) -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure a centerY relation to superview without superview.") @@ -782,7 +783,7 @@ public final class Maker { } return centerY(to: RelationView(view: superview, relation: .centerY), offset: offset.value) } - + /// Creates centerY relation. /// /// Use this method when you want to join centerY of current view with some vertical side of another view. @@ -793,11 +794,11 @@ public final class Maker { /// - parameter offset: Additional offset for centerY point. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func centerY(to relationView: RelationView, offset: Number = 0.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in let y = self.convertedValue(for: relationType, with: view) - self.newRect.height/2 - offset.value self.newRect.setValue(y, for: .top) @@ -805,7 +806,7 @@ public final class Maker { handlers.append((.low, handler)) return self } - + /// Creates centerY relation between two views. /// /// Use this method when you want to configure centerY point between two following views. @@ -814,7 +815,7 @@ public final class Maker { /// - parameter view2: The second view between which you set `centerY` relation. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func centerY(between view1: UIView, _ view2: UIView) -> Maker { let topView = view1.frame.maxY > view2.frame.minY ? view2 : view1 let bottomView = topView === view1 ? view2 : view1 @@ -859,7 +860,7 @@ public final class Maker { /// - parameter offset: Additional offset for centerX point. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func centerX(offset: Number = 0.0) -> Maker { guard let superview = view.superview else { assertionFailure("Can not configure a centerX relation to superview without superview.") @@ -867,7 +868,7 @@ public final class Maker { } return centerX(to: RelationView(view: superview, relation: .centerX), offset: offset.value) } - + /// Creates centerX relation. /// /// Use this method when you want to join centerX of current view with some horizontal side of another view. @@ -878,11 +879,11 @@ public final class Maker { /// - parameter offset: Additional offset for centerX point. Default value: 0. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func centerX(to relationView: RelationView, offset: Number = 0.0) -> Maker { let view = relationView.view let relationType = relationView.relationType - + let handler = { [unowned self] in let x = self.convertedValue(for: relationType, with: view) - self.newRect.width/2 - offset.value self.newRect.setValue(x, for: .left) @@ -890,7 +891,7 @@ public final class Maker { handlers.append((.low, handler)) return self } - + /// Creates centerX relation between two views. /// /// Use this method when you want to configure centerX point between two following views. @@ -899,7 +900,7 @@ public final class Maker { /// - parameter view2: The second view between which you set `centerX` relation. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func centerX(between view1: UIView, _ view2: UIView) -> Maker { let leftView = view1.frame.maxX > view2.frame.minX ? view2 : view1 let rightView = leftView === view1 ? view2 : view1 @@ -942,7 +943,7 @@ public final class Maker { /// - parameter value: The value for setting centerX. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func setCenterX(value: Number) -> Maker { let handler = { [unowned self] in self.newRect.setValue(value.value, for: .centerX) @@ -950,13 +951,13 @@ public final class Maker { handlers.append((.low, handler)) return self } - + /// Just setting centerY. /// /// - parameter value: The value for setting centerY. /// /// - returns: `Maker` instance for chaining relations. - + @discardableResult public func setCenterY(value: Number) -> Maker { let handler = { [unowned self] in self.newRect.setValue(value.value, for: .centerY) @@ -964,7 +965,7 @@ public final class Maker { handlers.append((.low, handler)) return self } - + // MARK: Private private func setHighPriorityValue(_ value: CGFloat, for relationType: RelationType) { @@ -972,7 +973,7 @@ public final class Maker { self.newRect.setValue(value, for: relationType) } handlers.append((.high, handler)) - + switch relationType { case .width: widthParameter = ValueParameter(value: value) case .height: heightParameter = ValueParameter(value: value) diff --git a/Sources/MakerHelper.swift b/Sources/MakerHelper.swift index 8b96394..b9273a5 100644 --- a/Sources/MakerHelper.swift +++ b/Sources/MakerHelper.swift @@ -9,7 +9,7 @@ import Foundation fileprivate extension UIView { - + func contains(_ view: UIView) -> Bool { if subviews.contains(view) { return true @@ -85,7 +85,7 @@ extension Maker { return 0 } } - + func relationSize(view: UIView, for type: RelationType) -> CGFloat { switch type { case .width: return view.bounds.width @@ -96,7 +96,7 @@ extension Maker { } extension CGRect { - + mutating func setValue(_ value: CGFloat, for type: RelationType) { var frame = self switch type { diff --git a/Sources/Parameters.swift b/Sources/Parameters.swift index d35a57a..f718159 100644 --- a/Sources/Parameters.swift +++ b/Sources/Parameters.swift @@ -17,11 +17,11 @@ final class ValueParameter { } final class SideParameter { - + unowned let view: UIView let value: CGFloat let relationType: RelationType - + init(view: UIView, value: CGFloat, relationType: RelationType) { self.view = view self.value = value diff --git a/Sources/UIView+Installer.swift b/Sources/UIView+Installer.swift index dd16c9e..603e76e 100644 --- a/Sources/UIView+Installer.swift +++ b/Sources/UIView+Installer.swift @@ -15,13 +15,13 @@ private var stateTypeAssociationKey: UInt8 = 0 private var nxStateTypeAssociationKey: UInt8 = 1 public extension UIView { - + /// Apply new configuration state without frame updating. /// /// - note: Use `DEFAULT_STATE` for setting the state to the default value. - + @available(*, message: "Renamed due to conflict with Objective-C library - Framer", unavailable, renamed: "nx_state") - public var nui_state: AnyHashable { + var nui_state: AnyHashable { get { if let value = objc_getAssociatedObject(self, &stateTypeAssociationKey) as? AnyHashable { return value @@ -34,12 +34,12 @@ public extension UIView { objc_setAssociatedObject(self, &stateTypeAssociationKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } } - + /// Apply new configuration state without frame updating. /// /// - note: Use `DEFAULT_STATE` for setting the state to the default value. - - public var nx_state: AnyHashable { + + var nx_state: AnyHashable { get { if let value = objc_getAssociatedObject(self, &nxStateTypeAssociationKey) as? AnyHashable { return value @@ -55,31 +55,39 @@ public extension UIView { } public extension UIView { - + @available(*, deprecated, renamed: "configureFrame(state:installerBlock:)") - public func configureFrames(state: AnyHashable = DEFAULT_STATE, installerBlock: InstallerBlock) { + func configureFrames(state: AnyHashable = DEFAULT_STATE, installerBlock: InstallerBlock) { Maker.configure(view: self, for: state, installerBlock: installerBlock) } - + /// Configures frame of current view for special state. /// /// - note: When you configure frame without implicit state parameter (default value), frame configures for the `DEFAULT_STATE`. /// /// - parameter state: The state for which you configure frame. Default value: `DEFAULT_STATE`. /// - parameter installerBlock: The installer block within which you can configure frame relations. - - public func configureFrame(state: AnyHashable = DEFAULT_STATE, installerBlock: InstallerBlock) { + + func configureFrame(state: AnyHashable = DEFAULT_STATE, installerBlock: InstallerBlock) { + guard self.superview != nil else { + return + } + Maker.configure(view: self, for: state, installerBlock: installerBlock) } - + /// Configures frame of current view for special states. /// /// - note: Don't forget about `DEFAULT_VALUE`. /// /// - parameter states: The states for which you configure frame. /// - parameter installerBlock: The installer block within which you can configure frame relations. - - public func configureFrame(states: [AnyHashable], installerBlock: InstallerBlock) { + + func configureFrame(states: [AnyHashable], installerBlock: InstallerBlock) { + guard self.superview != nil else { + return + } + for state in states { Maker.configure(view: self, for: state, installerBlock: installerBlock) } @@ -87,28 +95,28 @@ public extension UIView { } public extension Sequence where Iterator.Element: UIView { - + /// Configures frames of the views for special state. /// /// - note: When you configure frame without implicit state parameter (default value), frame configures for the `DEFAULT_STATE`. /// /// - parameter state: The state for which you configure frame. Default value: `DEFAULT_STATE`. /// - parameter installerBlock: The installer block within which you can configure frame relations. - - public func configureFrames(state: AnyHashable = DEFAULT_STATE, installerBlock: InstallerBlock) { + + func configureFrames(state: AnyHashable = DEFAULT_STATE, installerBlock: InstallerBlock) { for view in self { view.configureFrame(state: state, installerBlock: installerBlock) } } - + /// Configures frames of the views for special states. /// /// - note: Don't forget about `DEFAULT_VALUE`. /// /// - parameter states: The states for which you configure frames. /// - parameter installerBlock: The installer block within which you can configure frame relations. - - public func configureFrames(states: [AnyHashable], installerBlock: InstallerBlock) { + + func configureFrames(states: [AnyHashable], installerBlock: InstallerBlock) { for view in self { view.configureFrame(states: states, installerBlock: installerBlock) } @@ -140,22 +148,22 @@ public extension Collection where Iterator.Element: UIView { /// - `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) { + func configure(container: UIView, relation: ContainerRelation? = nil, installerBlock: () -> Void) { container.frame = .zero var relationWidth: CGFloat? var relationHeight: CGFloat? - + if let relation = relation { switch relation { case let .width(width): container.frame.size.width = width.value relationWidth = width.value - + case let .height(height): container.frame.size.height = height.value relationHeight = height.value - + case let .horizontal(lInset, rInset): container.configureFrame { maker in maker.left(inset: lInset).right(inset: rInset) @@ -164,7 +172,7 @@ public extension Collection where Iterator.Element: UIView { container.frame = .zero container.frame.size.width = width relationWidth = width - + case let .vertical(tInset, bInset): container.configureFrame { maker in maker.top(inset: tInset).bottom(inset: bInset) @@ -184,15 +192,15 @@ public extension Collection where Iterator.Element: UIView { container.configureFrame { maker in maker._container() } - + if let width = relationWidth { container.frame.size.width = width } - + if let height = relationHeight { container.frame.size.height = height } - + installerBlock() } @@ -214,7 +222,7 @@ public extension Collection where Iterator.Element: UIView { /// /// - returns: Container view. - public func container(in view: UIView, relation: ContainerRelation? = nil, installerBlock: () -> Void) -> UIView { + func container(in view: UIView, relation: ContainerRelation? = nil, installerBlock: () -> Void) -> UIView { let container: UIView if let superView = self.first?.superview { container = superView diff --git a/Sources/UIView+Relations.swift b/Sources/UIView+Relations.swift index 6aacfac..5d89835 100644 --- a/Sources/UIView+Relations.swift +++ b/Sources/UIView+Relations.swift @@ -22,7 +22,7 @@ public final class RelationView { unowned var view: UIView var relationType: RelationType - + init(view: UIView, relation: RelationType) { self.view = view self.relationType = relation @@ -50,13 +50,13 @@ enum RelationType { case safeArea(SafeAreaType) } -public struct SafeAreaRelationCollection { +public final class SafeAreaRelationCollection { unowned var view: UIView - lazy var top = RelationView(view: view, relation: .safeArea(.top)) - lazy var left = RelationView(view: view, relation: .safeArea(.left)) - lazy var right = RelationView(view: view, relation: .safeArea(.right)) - lazy var bottom = RelationView(view: view, relation: .safeArea(.bottom)) + public lazy var top: RelationView = .init(view: view, relation: .safeArea(.top)) + public lazy var left: RelationView = .init(view: view, relation: .safeArea(.left)) + public lazy var right: RelationView = .init(view: view, relation: .safeArea(.right)) + public lazy var bottom: RelationView = .init(view: view, relation: .safeArea(.bottom)) init(view: UIView) { self.view = view @@ -64,58 +64,58 @@ public struct SafeAreaRelationCollection { } public extension UIView { - + /// Width relation of current view. - - public var nui_width: RelationView { + + var nui_width: RelationView { return RelationView(view: self, relation: .width) } - + /// Height relation of current view. - - public var nui_height: RelationView { + + var nui_height: RelationView { return RelationView(view: self, relation: .height) } - + /// Left relation of current view. - public var nui_left: RelationView { + var nui_left: RelationView { return RelationView(view: self, relation: .left) } - + /// Right relation of current view. - - public var nui_right: RelationView { + + var nui_right: RelationView { return RelationView(view: self, relation: .right) } - + /// Top relation of current view. - - public var nui_top: RelationView { + + var nui_top: RelationView { return RelationView(view: self, relation: .top) } - + /// Bottom relation of current view. - - public var nui_bottom: RelationView { + + var nui_bottom: RelationView { return RelationView(view: self, relation: .bottom) } - + /// CenterX relation of current view. - - public var nui_centerX: RelationView { + + var nui_centerX: RelationView { return RelationView(view: self, relation: .centerX) } - + /// CenterY relation of current view. - - public var nui_centerY: RelationView { + + var nui_centerY: RelationView { return RelationView(view: self, relation: .centerY) } /// Safe area - public var nui_safeArea: SafeAreaRelationCollection { + var nui_safeArea: SafeAreaRelationCollection { return SafeAreaRelationCollection(view: self) } } From aea5127cbccc7a1a65c07961e592b88fd4fa45df Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 24 Apr 2019 15:39:30 +0600 Subject: [PATCH 3/8] Convert to swift 5 --- Framezilla.xcodeproj/project.pbxproj | 25 ++++++++++--------- .../xcschemes/Framezilla iOS.xcscheme | 8 +++--- Sources/Maker.swift | 4 +-- Tests/MakerTests.swift | 6 ++--- 4 files changed, 21 insertions(+), 22 deletions(-) diff --git a/Framezilla.xcodeproj/project.pbxproj b/Framezilla.xcodeproj/project.pbxproj index c4b1cb3..77c1f0a 100644 --- a/Framezilla.xcodeproj/project.pbxproj +++ b/Framezilla.xcodeproj/project.pbxproj @@ -206,26 +206,27 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0800; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 1020; TargetAttributes = { 115972131D8450F500BC5C20 = { CreatedOnToolsVersion = 8.0; - LastSwiftMigration = 0900; + LastSwiftMigration = 1020; ProvisioningStyle = Manual; }; 11FB41311D844D2B00700A40 = { CreatedOnToolsVersion = 8.0; - LastSwiftMigration = 0900; + LastSwiftMigration = 1020; ProvisioningStyle = Automatic; }; }; }; buildConfigurationList = 11FB412A1D844CD800700A40 /* Build configuration list for PBXProject "Framezilla" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 11FB41261D844CD800700A40; productRefGroup = 11FB41331D844D2C00700A40 /* Products */; @@ -370,8 +371,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OBJC_BRIDGING_HEADER = "Tests/FramezillaTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -420,8 +420,7 @@ SDKROOT = iphoneos; SWIFT_OBJC_BRIDGING_HEADER = "Tests/FramezillaTests-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -433,11 +432,13 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; @@ -464,11 +465,13 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; @@ -544,8 +547,7 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -602,8 +604,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_SWIFT3_OBJC_INFERENCE = On; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/Framezilla.xcodeproj/xcshareddata/xcschemes/Framezilla iOS.xcscheme b/Framezilla.xcodeproj/xcshareddata/xcschemes/Framezilla iOS.xcscheme index c462db0..98f180d 100644 --- a/Framezilla.xcodeproj/xcshareddata/xcschemes/Framezilla iOS.xcscheme +++ b/Framezilla.xcodeproj/xcshareddata/xcschemes/Framezilla iOS.xcscheme @@ -1,6 +1,6 @@ + codeCoverageEnabled = "YES" + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -57,7 +56,6 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - language = "" launchStyle = "0" useCustomWorkingDirectory = "NO" ignoresPersistentStateOnLaunch = "NO" diff --git a/Sources/Maker.swift b/Sources/Maker.swift index 595a33c..14daa04 100644 --- a/Sources/Maker.swift +++ b/Sources/Maker.swift @@ -626,7 +626,7 @@ public final class Maker { let handler = { [unowned self] in if self.topParameter != nil { - let height = fabs(self.newRect.minY - self.convertedValue(for: relationType, with: view)) - inset.value + let height = abs(self.newRect.minY - self.convertedValue(for: relationType, with: view)) - inset.value self.newRect.setValue(height, for: .height) } else { @@ -697,7 +697,7 @@ public final class Maker { let handler = { [unowned self] in if self.leftParameter != nil { - let width = fabs(self.newRect.minX - self.convertedValue(for: relationType, with: view)) - inset.value + let width = abs(self.newRect.minX - self.convertedValue(for: relationType, with: view)) - inset.value self.newRect.setValue(width, for: .width) } else { diff --git a/Tests/MakerTests.swift b/Tests/MakerTests.swift index 95a3368..33e34d0 100644 --- a/Tests/MakerTests.swift +++ b/Tests/MakerTests.swift @@ -337,7 +337,7 @@ class MakerTests: BaseTest { func testThatCorrectlyConfigures_equal_to_relationForNearSubview() { - let insets = UIEdgeInsetsMake(5, 10, 15, 20) + let insets = UIEdgeInsets(top: 5, left: 10, bottom: 15, right: 20) testingView.configureFrame { maker in maker.equal(to: nestedView1, insets: insets) } @@ -357,7 +357,7 @@ class MakerTests: BaseTest { func testThatCorrectlyConfigures_edge_insets_toSuperview() { testingView.configureFrame { maker in - maker.edges(insets: UIEdgeInsetsMake(10, 20, 40, 60)) + maker.edges(insets: UIEdgeInsets(top: 10, left: 20, bottom: 40, right: 60)) } XCTAssertEqual(testingView.frame, CGRect(x: 20, y: 10, width: 420, height: 450)) } @@ -382,7 +382,7 @@ class MakerTests: BaseTest { containet.addSubview(view2) containet.configureFrame { maker in - maker._container() + maker.container() } XCTAssertEqual(containet.frame, CGRect(x: 0, y: 0, width: 120, height: 120)) } From 9854aca23e6637e684b5b8965c7354091a7dd437 Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 24 Apr 2019 15:45:41 +0600 Subject: [PATCH 4/8] Update safe area tests --- Tests/MakerSafeAreaTests.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Tests/MakerSafeAreaTests.swift b/Tests/MakerSafeAreaTests.swift index d12fa19..78e8310 100644 --- a/Tests/MakerSafeAreaTests.swift +++ b/Tests/MakerSafeAreaTests.swift @@ -39,7 +39,7 @@ class MakerSafeAreaTests: XCTestCase { viewController.view.addSubview(view) view.configureFrame { maker in - maker.top(to: nui_safeArea) + maker.top(to: viewController.view.nui_safeArea.top) maker.left() maker.size(width: 20, height: 20) } @@ -62,7 +62,7 @@ class MakerSafeAreaTests: XCTestCase { let inset: CGFloat = 5 view.configureFrame { maker in - maker.top(to: nui_safeArea, inset: inset) + maker.top(to: viewController.view.nui_safeArea.top, inset: inset) maker.left() maker.size(width: 20, height: 20) } @@ -87,7 +87,7 @@ class MakerSafeAreaTests: XCTestCase { view.configureFrame { maker in maker.top() - maker.left(to: nui_safeArea) + maker.left(to: viewController.view.nui_safeArea.left) maker.size(width: 20, height: 20) } @@ -110,7 +110,7 @@ class MakerSafeAreaTests: XCTestCase { let inset: CGFloat = 5 view.configureFrame { maker in maker.top() - maker.left(to: nui_safeArea, inset: inset) + maker.left(to: viewController.view.nui_safeArea.left, inset: inset) maker.size(width: 20, height: 20) } @@ -139,7 +139,7 @@ class MakerSafeAreaTests: XCTestCase { viewController.view.addSubview(view) view.configureFrame { maker in - maker.bottom(to: nui_safeArea) + maker.bottom(to: viewController.view.nui_safeArea.bottom) maker.left() maker.size(width: 20, height: 20) } @@ -168,7 +168,7 @@ class MakerSafeAreaTests: XCTestCase { let inset: CGFloat = 5 view.configureFrame { maker in - maker.bottom(to: nui_safeArea, inset: inset) + maker.bottom(to: viewController.view.nui_safeArea.bottom, inset: inset) maker.left() maker.size(width: 20, height: 20) } @@ -198,7 +198,7 @@ class MakerSafeAreaTests: XCTestCase { viewController.view.addSubview(view) view.configureFrame { maker in - maker.right(to: nui_safeArea) + maker.right(to: viewController.view.nui_safeArea.right) maker.bottom() maker.size(width: 20, height: 20) } @@ -227,7 +227,7 @@ class MakerSafeAreaTests: XCTestCase { let inset: CGFloat = 5 view.configureFrame { maker in - maker.right(to: nui_safeArea, inset: inset) + maker.right(to: viewController.view.nui_safeArea.right, inset: inset) maker.bottom() maker.size(width: 20, height: 20) } From c4b209270789c5e127eff60be5c977f57167865c Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 24 Apr 2019 15:55:48 +0600 Subject: [PATCH 5/8] Retire podspec --- Framezilla.podspec | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 Framezilla.podspec diff --git a/Framezilla.podspec b/Framezilla.podspec deleted file mode 100644 index b61f34e..0000000 --- a/Framezilla.podspec +++ /dev/null @@ -1,15 +0,0 @@ -Pod::Spec.new do |spec| - spec.name = "Framezilla" - spec.version = "2.9.1" - spec.summary = "Comfortable syntax for working with frames." - - spec.homepage = "https://github.com/Otbivnoe/Framezilla" - spec.license = { type: 'MIT', file: 'LICENSE' } - spec.authors = { "Nikita Ermolenko" => 'gnod94@gmail.com' } - spec.platform = :ios - spec.requires_arc = true - - spec.ios.deployment_target = '8.4' - spec.source = { git: "https://github.com/Otbivnoe/Framezilla.git", tag: "#{spec.version}"} - spec.source_files = "Sources/*.{h,swift}" -end From 14e5bc5ce07ed7c6840f9e2d32f4e93da7e9367d Mon Sep 17 00:00:00 2001 From: Rosberry Date: Wed, 24 Apr 2019 15:57:08 +0600 Subject: [PATCH 6/8] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0cb4a0d..8b5559e 100644 --- a/README.md +++ b/README.md @@ -127,10 +127,10 @@ In iOS 11 Apple has introduced the safe area, similar to `topLayoutGuide` and `b ```swift content.configureFrame { maker in - maker.top(to: nui_safeArea) - maker.bottom(to: nui_safeArea) - maker.right(to: nui_safeArea, inset: 10) - maker.left(to: nui_safeArea, inset: 10) + maker.top(to: view.nui_safeArea.top) + maker.bottom(to: view.nui_safeArea.bottom) + maker.right(to: view.nui_safeArea.right, inset: 10) + maker.left(to: view.nui_safeArea.left, inset: 10) } ``` From 03007edba51c5710ea4cc2d68c1cae3efdaf54ec Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 24 Apr 2019 16:06:33 +0600 Subject: [PATCH 7/8] Fix failing testcases --- Framezilla.xcodeproj/project.pbxproj | 2 -- Tests/MakerTests.swift | 36 ++++++++++++++-------------- Tests/MakerWidthHeightTests.swift | 8 +++++++ Tests/StateTests.swift | 4 ++++ 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/Framezilla.xcodeproj/project.pbxproj b/Framezilla.xcodeproj/project.pbxproj index 77c1f0a..b818d40 100644 --- a/Framezilla.xcodeproj/project.pbxproj +++ b/Framezilla.xcodeproj/project.pbxproj @@ -50,7 +50,6 @@ 11FB41421D844F8F00700A40 /* MakerHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MakerHelper.swift; sourceTree = ""; }; 11FB41431D844F8F00700A40 /* UIView+Installer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Installer.swift"; sourceTree = ""; }; 11FB41441D844F8F00700A40 /* UIView+Relations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Relations.swift"; sourceTree = ""; }; - 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 /* ContainerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerTests.swift; sourceTree = ""; }; @@ -93,7 +92,6 @@ 11FB41261D844CD800700A40 = { isa = PBXGroup; children = ( - 11FB414A1D844FFA00700A40 /* Framezilla.podspec */, 11FB414B1D844FFA00700A40 /* LICENSE */, 11FB414C1D844FFA00700A40 /* README.md */, 11FB413B1D844D5A00700A40 /* Sources */, diff --git a/Tests/MakerTests.swift b/Tests/MakerTests.swift index 33e34d0..12cb35a 100644 --- a/Tests/MakerTests.swift +++ b/Tests/MakerTests.swift @@ -13,9 +13,12 @@ class MakerTests: BaseTest { /* Array configurator */ func testThatCorrectlyConfiguresFramesForArrayOfViews() { - + let label = UILabel(frame: .zero) + testingView.addSubview(label) + let view = UIView(frame: .zero) + testingView.addSubview(view) [label, view].configureFrames { maker in maker.width(100) @@ -377,14 +380,15 @@ class MakerTests: BaseTest { let view1 = UIView(frame: CGRect(x: 50, y: 50, width: 50, height: 50)) let view2 = UIView(frame: CGRect(x: 70, y: 70, width: 50, height: 50)) - let containet = UIView() - containet.addSubview(view1) - containet.addSubview(view2) + let container = UIView() + container.addSubview(view1) + container.addSubview(view2) + testingView.addSubview(container) - containet.configureFrame { maker in + container.configureFrame { maker in maker.container() } - XCTAssertEqual(containet.frame, CGRect(x: 0, y: 0, width: 120, height: 120)) + XCTAssertEqual(container.frame, CGRect(x: 0, y: 0, width: 120, height: 120)) } /* sizeToFit */ @@ -393,6 +397,7 @@ class MakerTests: BaseTest { let label = UILabel() label.text = "Hello" + testingView.addSubview(label) label.configureFrame { maker in maker.sizeToFit() @@ -407,6 +412,7 @@ class MakerTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.sizeThatFits(size: CGSize(width: 30, height: 0)) @@ -418,31 +424,25 @@ class MakerTests: BaseTest { /* corner radius */ func testThat_cornerRadius_correctlyConfigures() { - let view = UIView() - - view.configureFrame { maker in + testingView.configureFrame { maker in maker.cornerRadius(100) } - XCTAssertEqual(view.layer.cornerRadius, 100) + XCTAssertEqual(testingView.layer.cornerRadius, 100) } func testThat_cornerRadiusWithHalfWidth_correctlyConfigures() { - let view = UIView() - - view.configureFrame { maker in + testingView.configureFrame { maker in maker.width(100) maker.cornerRadius(byHalf: .width) } - XCTAssertEqual(view.layer.cornerRadius, 50) + XCTAssertEqual(testingView.layer.cornerRadius, 50) } func testThat_cornerRadiusWithHalfHeight_correctlyConfigures() { - let view = UIView() - - view.configureFrame { maker in + testingView.configureFrame { maker in maker.height(100) maker.cornerRadius(byHalf: .height) } - XCTAssertEqual(view.layer.cornerRadius, 50) + XCTAssertEqual(testingView.layer.cornerRadius, 50) } } diff --git a/Tests/MakerWidthHeightTests.swift b/Tests/MakerWidthHeightTests.swift index 9053a3d..d0fb063 100644 --- a/Tests/MakerWidthHeightTests.swift +++ b/Tests/MakerWidthHeightTests.swift @@ -195,6 +195,7 @@ class MakerWidthHeightTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.heightToFit() @@ -206,6 +207,7 @@ class MakerWidthHeightTests: BaseTest { func testHeightToFit_withWidthRelation() { let view = HeightFitView() + testingView.addSubview(view) view.configureFrame { maker in maker.heightToFit() @@ -246,6 +248,7 @@ class MakerWidthHeightTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.widthToFit() @@ -257,6 +260,7 @@ class MakerWidthHeightTests: BaseTest { func testWidthToFit_withHeightRelation() { let view = WidthFitView() + testingView.addSubview(view) view.configureFrame { maker in maker.widthToFit() @@ -299,6 +303,7 @@ class MakerWidthHeightTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.widthThatFits(maxWidth: 30) @@ -311,6 +316,7 @@ class MakerWidthHeightTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.widthThatFits(maxWidth: 300) @@ -323,6 +329,7 @@ class MakerWidthHeightTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.heightThatFits(maxHeight: 5) @@ -335,6 +342,7 @@ class MakerWidthHeightTests: BaseTest { let label = UILabel() label.text = "HelloHelloHelloHello" + testingView.addSubview(label) label.configureFrame { maker in maker.heightThatFits(maxHeight: 300) diff --git a/Tests/StateTests.swift b/Tests/StateTests.swift index e280dd7..1127c31 100644 --- a/Tests/StateTests.swift +++ b/Tests/StateTests.swift @@ -44,6 +44,7 @@ class StateTests: BaseTest { private func configureFramesForSingleView() { view1.frame = .zero + testingView.addSubview(view1) view1.configureFrame { maker in maker.width(10) @@ -93,7 +94,10 @@ class StateTests: BaseTest { private func configureFramesForArrayOfViews() { view1.frame = .zero + testingView.addSubview(view1) + view2.frame = .zero + testingView.addSubview(view2) [view1, view2].configureFrames { maker in maker.width(10) From 1ad8bc8a4e4c141255db4e891a614089f3e9e881 Mon Sep 17 00:00:00 2001 From: Anton Kormakov Date: Wed, 21 Aug 2019 12:52:35 +0600 Subject: [PATCH 8/8] Make view.nui_safeArea available only from iOS 11 --- Sources/UIView+Relations.swift | 2 + Tests/MakerSafeAreaTests.swift | 164 ++++++++++++--------------------- 2 files changed, 61 insertions(+), 105 deletions(-) diff --git a/Sources/UIView+Relations.swift b/Sources/UIView+Relations.swift index 5d89835..40f78b9 100644 --- a/Sources/UIView+Relations.swift +++ b/Sources/UIView+Relations.swift @@ -50,6 +50,7 @@ enum RelationType { case safeArea(SafeAreaType) } +@available(iOS 11.0, *) public final class SafeAreaRelationCollection { unowned var view: UIView @@ -115,6 +116,7 @@ public extension UIView { /// Safe area + @available(iOS 11.0, *) var nui_safeArea: SafeAreaRelationCollection { return SafeAreaRelationCollection(view: self) } diff --git a/Tests/MakerSafeAreaTests.swift b/Tests/MakerSafeAreaTests.swift index 78e8310..152d3d8 100644 --- a/Tests/MakerSafeAreaTests.swift +++ b/Tests/MakerSafeAreaTests.swift @@ -31,34 +31,31 @@ class MakerSafeAreaTests: XCTestCase { /* top */ func testThatCorrectlyConfigures_top_to_SafeArea() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.top = 10 + guard #available(iOS 11.0, *) else { + return } let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.top = 10 view.configureFrame { maker in maker.top(to: viewController.view.nui_safeArea.top) maker.left() maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: 0, y: viewController.additionalSafeAreaInsets.top, width: 20, height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: 0, y: 0, width: 20, height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: 0, y: viewController.additionalSafeAreaInsets.top, width: 20, height: 20)) } func testThatCorrectlyConfigures_top_to_SafeAreaWithInset() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.top = 10 + guard #available(iOS 11.0, *) else { + return } - + let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.top = 10 let inset: CGFloat = 5 view.configureFrame { maker in @@ -66,46 +63,38 @@ class MakerSafeAreaTests: XCTestCase { maker.left() maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: 0, y: viewController.additionalSafeAreaInsets.top + inset, width: 20, height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: 0, y: inset, width: 20, height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: 0, y: viewController.additionalSafeAreaInsets.top + inset, width: 20, height: 20)) } /* left */ func testThatCorrectlyConfigures_left_to_SafeArea() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.left = 10 + guard #available(iOS 11.0, *) else { + return } let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.left = 10 view.configureFrame { maker in maker.top() maker.left(to: viewController.view.nui_safeArea.left) maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: viewController.additionalSafeAreaInsets.left, y: 0, width: 20, height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: 0, y: 0, width: 20, height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: viewController.additionalSafeAreaInsets.left, y: 0, width: 20, height: 20)) } func testThatCorrectlyConfigures_left_to_SafeAreaWithInset() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.left = 10 + guard #available(iOS 11.0, *) else { + return } - + let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.left = 10 let inset: CGFloat = 5 view.configureFrame { maker in @@ -113,58 +102,45 @@ class MakerSafeAreaTests: XCTestCase { maker.left(to: viewController.view.nui_safeArea.left, inset: inset) maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: viewController.additionalSafeAreaInsets.left + inset, - y: 0, - width: 20, - height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: inset, - y: 0, - width: 20, - height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: viewController.additionalSafeAreaInsets.left + inset, + y: 0, + width: 20, + height: 20)) } /* bottom */ func testThatCorrectlyConfigures_bottom_to_SafeArea() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.bottom = 10 + guard #available(iOS 11.0, *) else { + return } + let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.bottom = 10 view.configureFrame { maker in maker.bottom(to: viewController.view.nui_safeArea.bottom) maker.left() maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: 0, - y: viewController.view.frame.height - viewController.additionalSafeAreaInsets.bottom - 20, - width: 20, - height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: 0, - y: viewController.view.frame.height - 20, - width: 20, - height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: 0, + y: viewController.view.frame.height - viewController.additionalSafeAreaInsets.bottom - 20, + width: 20, + height: 20)) } func testThatCorrectlyConfigures_bottom_to_SafeAreaWithInset() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.bottom = 10 + guard #available(iOS 11.0, *) else { + return } let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.bottom = 10 let inset: CGFloat = 5 view.configureFrame { maker in @@ -172,58 +148,44 @@ class MakerSafeAreaTests: XCTestCase { maker.left() maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: 0, - y: viewController.view.frame.height - viewController.additionalSafeAreaInsets.bottom - 20 - inset, - width: 20, - height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: 0, - y: viewController.view.frame.height - 20 - inset, - width: 20, - height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: 0, + y: viewController.view.frame.height - viewController.additionalSafeAreaInsets.bottom - 20 - inset, + width: 20, + height: 20)) } /* right */ func testThatCorrectlyConfigures_right_to_SafeArea() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.right = 10 + guard #available(iOS 11.0, *) else { + return } - + let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.right = 10 view.configureFrame { maker in maker.right(to: viewController.view.nui_safeArea.right) maker.bottom() maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: viewController.view.frame.width - viewController.additionalSafeAreaInsets.right - 20, - y: viewController.view.frame.height - 20, - width: 20, - height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: viewController.view.frame.width - 20, - y: viewController.view.frame.height - 20, - width: 20, - height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: viewController.view.frame.width - viewController.additionalSafeAreaInsets.right - 20, + y: viewController.view.frame.height - 20, + width: 20, + height: 20)) } func testThatCorrectlyConfigures_right_to_SafeAreaWithInset() { - if #available(iOS 11.0, *) { - viewController.additionalSafeAreaInsets.right = 10 + guard #available(iOS 11.0, *) else { + return } let view = UIView() viewController.view.addSubview(view) + viewController.additionalSafeAreaInsets.right = 10 let inset: CGFloat = 5 view.configureFrame { maker in @@ -231,18 +193,10 @@ class MakerSafeAreaTests: XCTestCase { maker.bottom() maker.size(width: 20, height: 20) } - - if #available(iOS 11.0, *) { - XCTAssertEqual(view.frame, CGRect(x: viewController.view.frame.width - viewController.additionalSafeAreaInsets.right - 20 - inset, - y: viewController.view.frame.height - 20, - width: 20, - height: 20)) - } - else { - XCTAssertEqual(view.frame, CGRect(x: viewController.view.frame.width - 20 - inset, - y: viewController.view.frame.height - 20, - width: 20, - height: 20)) - } + + XCTAssertEqual(view.frame, CGRect(x: viewController.view.frame.width - viewController.additionalSafeAreaInsets.right - 20 - inset, + y: viewController.view.frame.height - 20, + width: 20, + height: 20)) } }