From 931d6ca7ec228b734a4343457e378d0c9c791d7e Mon Sep 17 00:00:00 2001 From: Robert Payne Date: Sat, 11 Apr 2015 23:39:12 +1200 Subject: [PATCH] Initial Implementation of protocol API --- CHANGELOG.md | 2 + Source/Constraint.swift | 362 ++++++++++++++++++++++++---------- Source/ConstraintMaker.swift | 54 ++--- Source/LayoutConstraint.swift | 2 +- Source/View+Snap.swift | 2 +- Tests/Tests.swift | 4 +- 6 files changed, 293 insertions(+), 133 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bcfdd2..d263bfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ CHANGELOG # 0.10.0 - Next Release In Development * **BREAKING:** Using `.equalTo()` will no longer multiply the constants on the right/bottom edge by -1. This does not affect `.offset()` +* **BREAKING:** The constraint making chain now utilises protocols to tighten the API's to avoid user error. This may break some syntaxes. +* **BREAKING:** Semantic `and` and `with` chain variables were removed * Ensure Swift 1.2 compatibility * Added a `Snap.Config.interfaceLayoutDirection` variable for richer Leading/Trailing support. * Fixed memory leaks that could occur on long lived views diff --git a/Source/Constraint.swift b/Source/Constraint.swift index 148d412..a0d0477 100644 --- a/Source/Constraint.swift +++ b/Source/Constraint.swift @@ -28,270 +28,430 @@ import AppKit #endif /** - * Constraint is a single item that defines all the properties for a single ConstraintMaker chain - */ -final public class Constraint { - public var left: Constraint { return self.addConstraint(ConstraintAttributes.Left) } - public var top: Constraint { return self.addConstraint(ConstraintAttributes.Top) } - public var right: Constraint { return self.addConstraint(ConstraintAttributes.Right) } - public var bottom: Constraint { return self.addConstraint(ConstraintAttributes.Bottom) } - public var leading: Constraint { return self.addConstraint(ConstraintAttributes.Leading) } - public var trailing: Constraint { return self.addConstraint(ConstraintAttributes.Trailing) } - public var width: Constraint { return self.addConstraint(ConstraintAttributes.Width) } - public var height: Constraint { return self.addConstraint(ConstraintAttributes.Height) } - public var centerX: Constraint { return self.addConstraint(ConstraintAttributes.CenterX) } - public var centerY: Constraint { return self.addConstraint(ConstraintAttributes.CenterY) } - public var baseline: Constraint { return self.addConstraint(ConstraintAttributes.Baseline) } +* Constraint is a protocol that exposes the public methods on a Constraint +*/ +public protocol Constraint: class { - public var and: Constraint { - if self.relation != nil { - fatalError("And is semantic only and can only be used before a relation is set.") - } - return self - } - public var with: Constraint { return self } + func install() -> [LayoutConstraint] + func uninstall() -> Void + func activate() -> Void + func deactivate() -> Void + +} + +public protocol ConstraintFinalizable: class { + + var constraint: Constraint { get } + +} + +/** + * ConstraintPriortizable is a protocol that allows a constraint to be prioritized + */ +public protocol ConstraintPriortizable: ConstraintFinalizable { + + func priority(priority: Float) -> ConstraintFinalizable + func priority(priority: Double) -> ConstraintFinalizable + func priority(priority: CGFloat) -> ConstraintFinalizable + func priority(priority: UInt) -> ConstraintFinalizable + func priority(priority: Int) -> ConstraintFinalizable + func priorityRequired() -> ConstraintFinalizable + func priorityHigh() -> ConstraintFinalizable + func priorityMedium() -> ConstraintFinalizable + func priorityLow() -> ConstraintFinalizable +} + +/** + * ConstraintMultipliable is a protocol that allows a constraint to be multiplied + */ +public protocol ConstraintMultipliable: ConstraintPriortizable { + + func multipliedBy(amount: Float) -> ConstraintPriortizable + func multipliedBy(amount: Double) -> ConstraintPriortizable + func multipliedBy(amount: CGFloat) -> ConstraintPriortizable + func multipliedBy(amount: Int) -> ConstraintPriortizable + func multipliedBy(amount: UInt) -> ConstraintPriortizable + + func dividedBy(amount: Float) -> ConstraintPriortizable + func dividedBy(amount: Double) -> ConstraintPriortizable + func dividedBy(amount: CGFloat) -> ConstraintPriortizable + func dividedBy(amount: Int) -> ConstraintPriortizable + func dividedBy(amount: UInt) -> ConstraintPriortizable +} + +/** + * ConstraintOffsetable is a protocol that allows a constraint to be offset + */ +public protocol ConstraintOffsetable: ConstraintMultipliable { + + func offset(amount: Float) -> ConstraintMultipliable + func offset(amount: Double) -> ConstraintMultipliable + func offset(amount: CGFloat) -> ConstraintMultipliable + func offset(amount: Int) -> ConstraintMultipliable + func offset(amount: UInt) -> ConstraintMultipliable + func offset(amount: CGPoint) -> ConstraintMultipliable + func offset(amount: CGSize) -> ConstraintMultipliable + func offset(amount: EdgeInsets) -> ConstraintMultipliable + + func insets(amount: EdgeInsets) -> ConstraintMultipliable +} + + + +/** + * ConstraintRelatable is a protocol that allows a constraint to be set related to another item/constant by equalTo, lessThanOrEqualTo or greaterThanOrEqualTo + */ +public protocol ConstraintRelatable: class { + + func equalTo(other: ConstraintItem) -> ConstraintOffsetable + func equalTo(other: View) -> ConstraintOffsetable + #if os(iOS) + func equalTo(other: UILayoutSupport) -> ConstraintOffsetable + #endif + func equalTo(other: Float) -> ConstraintMultipliable + func equalTo(other: Double) -> ConstraintMultipliable + func equalTo(other: CGFloat) -> ConstraintMultipliable + func equalTo(other: Int) -> ConstraintMultipliable + func equalTo(other: UInt) -> ConstraintMultipliable + func equalTo(other: CGSize) -> ConstraintMultipliable + func equalTo(other: CGPoint) -> ConstraintMultipliable + func equalTo(other: EdgeInsets) -> ConstraintMultipliable + + func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintOffsetable + func lessThanOrEqualTo(other: View) -> ConstraintOffsetable + #if os(iOS) + func lessThanOrEqualTo(other: UILayoutSupport) -> ConstraintOffsetable + #endif + func lessThanOrEqualTo(other: Float) -> ConstraintMultipliable + func lessThanOrEqualTo(other: Double) -> ConstraintMultipliable + func lessThanOrEqualTo(other: CGFloat) -> ConstraintMultipliable + func lessThanOrEqualTo(other: Int) -> ConstraintMultipliable + func lessThanOrEqualTo(other: UInt) -> ConstraintMultipliable + func lessThanOrEqualTo(other: CGSize) -> ConstraintMultipliable + func lessThanOrEqualTo(other: CGPoint) -> ConstraintMultipliable + func lessThanOrEqualTo(other: EdgeInsets) -> ConstraintMultipliable + + func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintOffsetable + func greaterThanOrEqualTo(other: View) -> ConstraintOffsetable + #if os(iOS) + func greaterThanOrEqualTo(other: UILayoutSupport) -> ConstraintOffsetable + #endif + func greaterThanOrEqualTo(other: Float) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: Double) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: CGFloat) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: Int) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: UInt) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: CGSize) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: CGPoint) -> ConstraintMultipliable + func greaterThanOrEqualTo(other: EdgeInsets) -> ConstraintMultipliable + +} + +/** +* ConstraintExtendable is a protocol that allows a constraint to be extended +*/ +public protocol ConstraintExtendable: ConstraintRelatable { + + var left: ConstraintExtendable { get } + var top: ConstraintExtendable { get } + var bottom: ConstraintExtendable { get } + var leading: ConstraintExtendable { get } + var trailing: ConstraintExtendable { get } + var width: ConstraintExtendable { get } + var height: ConstraintExtendable { get } + var centerX: ConstraintExtendable { get } + var centerY: ConstraintExtendable { get } + var baseline: ConstraintExtendable { get } + + #if os(iOS) + var firstBaseline: ConstraintExtendable { get } + var leftMargin: ConstraintExtendable { get } + var rightMargin: ConstraintExtendable { get } + var topMargin: ConstraintExtendable { get } + var bottomMargin: ConstraintExtendable { get } + var leadingMargin: ConstraintExtendable { get } + var trailingMargin: ConstraintExtendable { get } + var centerXWithinMargins: ConstraintExtendable { get } + var centerYWithinMargins: ConstraintExtendable { get } + #endif +} + +/** + * MutableConstraint is a single item that defines all the properties for a single ConstraintMaker chain + */ +final internal class MutableConstraint: Constraint, ConstraintExtendable, ConstraintOffsetable, ConstraintFinalizable { + + var left: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Left) } + var top: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Top) } + var right: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Right) } + var bottom: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Bottom) } + var leading: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Leading) } + var trailing: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Trailing) } + var width: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Width) } + var height: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Height) } + var centerX: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterX) } + var centerY: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterY) } + var baseline: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Baseline) } + + #if os(iOS) + var firstBaseline: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.FirstBaseline) } + var leftMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.LeftMargin) } + var rightMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.RightMargin) } + var topMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.TopMargin) } + var bottomMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.BottomMargin) } + var leadingMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.LeadingMargin) } + var trailingMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.TrailingMargin) } + var centerXWithinMargins: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } + var centerYWithinMargins: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } + #endif // MARK: initializer - internal init(fromItem: ConstraintItem) { + init(fromItem: ConstraintItem) { self.fromItem = fromItem self.toItem = ConstraintItem(object: nil, attributes: ConstraintAttributes.None) } // MARK: equalTo - public func equalTo(other: ConstraintItem) -> Constraint { + func equalTo(other: ConstraintItem) -> ConstraintOffsetable { return self.constrainTo(other, relation: .Equal) } - public func equalTo(other: View) -> Constraint { + func equalTo(other: View) -> ConstraintOffsetable { return self.constrainTo(other, relation: .Equal) } #if os(iOS) - public func equalTo(other: UILayoutSupport) -> Constraint { + func equalTo(other: UILayoutSupport) -> ConstraintOffsetable { return self.constrainTo(other, relation: .Equal) } #endif - public func equalTo(other: Float) -> Constraint { + func equalTo(other: Float) -> ConstraintMultipliable { return self.constrainTo(other, relation: .Equal) } - public func equalTo(other: Double) -> Constraint { + func equalTo(other: Double) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .Equal) } - public func equalTo(other: CGFloat) -> Constraint { + func equalTo(other: CGFloat) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .Equal) } - public func equalTo(other: Int) -> Constraint { + func equalTo(other: Int) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .Equal) } - public func equalTo(other: UInt) -> Constraint { + func equalTo(other: UInt) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .Equal) } - public func equalTo(other: CGSize) -> Constraint { + func equalTo(other: CGSize) -> ConstraintMultipliable { return self.constrainTo(other, relation: .Equal) } - public func equalTo(other: CGPoint) -> Constraint { + func equalTo(other: CGPoint) -> ConstraintMultipliable { return self.constrainTo(other, relation: .Equal) } - public func equalTo(other: EdgeInsets) -> Constraint { + func equalTo(other: EdgeInsets) -> ConstraintMultipliable { return self.constrainTo(other, relation: .Equal) } // MARK: lessThanOrEqualTo - public func lessThanOrEqualTo(other: ConstraintItem) -> Constraint { + func lessThanOrEqualTo(other: ConstraintItem) -> ConstraintOffsetable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: View) -> Constraint { + func lessThanOrEqualTo(other: View) -> ConstraintOffsetable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } #if os(iOS) - public func lessThanOrEqualTo(other: UILayoutSupport) -> Constraint { + func lessThanOrEqualTo(other: UILayoutSupport) -> ConstraintOffsetable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } #endif - public func lessThanOrEqualTo(other: Float) -> Constraint { + func lessThanOrEqualTo(other: Float) -> ConstraintMultipliable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: Double) -> Constraint { + func lessThanOrEqualTo(other: Double) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: CGFloat) -> Constraint { + func lessThanOrEqualTo(other: CGFloat) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: Int) -> Constraint { + func lessThanOrEqualTo(other: Int) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: UInt) -> Constraint { + func lessThanOrEqualTo(other: UInt) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: CGSize) -> Constraint { + func lessThanOrEqualTo(other: CGSize) -> ConstraintMultipliable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: CGPoint) -> Constraint { + func lessThanOrEqualTo(other: CGPoint) -> ConstraintMultipliable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } - public func lessThanOrEqualTo(other: EdgeInsets) -> Constraint { + func lessThanOrEqualTo(other: EdgeInsets) -> ConstraintMultipliable { return self.constrainTo(other, relation: .LessThanOrEqualTo) } // MARK: greaterThanOrEqualTo - public func greaterThanOrEqualTo(other: ConstraintItem) -> Constraint { + func greaterThanOrEqualTo(other: ConstraintItem) -> ConstraintOffsetable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: View) -> Constraint { + func greaterThanOrEqualTo(other: View) -> ConstraintOffsetable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } #if os(iOS) - public func greaterThanOrEqualTo(other: UILayoutSupport) -> Constraint { + func greaterThanOrEqualTo(other: UILayoutSupport) -> ConstraintOffsetable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } #endif - public func greaterThanOrEqualTo(other: Float) -> Constraint { + func greaterThanOrEqualTo(other: Float) -> ConstraintMultipliable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: Double) -> Constraint { + func greaterThanOrEqualTo(other: Double) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: CGFloat) -> Constraint { + func greaterThanOrEqualTo(other: CGFloat) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: Int) -> Constraint { + func greaterThanOrEqualTo(other: Int) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: UInt) -> Constraint { + func greaterThanOrEqualTo(other: UInt) -> ConstraintMultipliable { return self.constrainTo(Float(other), relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: CGSize) -> Constraint { + func greaterThanOrEqualTo(other: CGSize) -> ConstraintMultipliable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: CGPoint) -> Constraint { + func greaterThanOrEqualTo(other: CGPoint) -> ConstraintMultipliable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } - public func greaterThanOrEqualTo(other: EdgeInsets) -> Constraint { + func greaterThanOrEqualTo(other: EdgeInsets) -> ConstraintMultipliable { return self.constrainTo(other, relation: .GreaterThanOrEqualTo) } // MARK: multiplier - public func multipliedBy(amount: Float) -> Constraint { + func multipliedBy(amount: Float) -> ConstraintPriortizable { self.multiplier = amount return self } - public func multipliedBy(amount: Double) -> Constraint { + func multipliedBy(amount: Double) -> ConstraintPriortizable { return self.multipliedBy(Float(amount)) } - public func multipliedBy(amount: CGFloat) -> Constraint { + func multipliedBy(amount: CGFloat) -> ConstraintPriortizable { return self.multipliedBy(Float(amount)) } - public func multipliedBy(amount: Int) -> Constraint { + func multipliedBy(amount: Int) -> ConstraintPriortizable { return self.multipliedBy(Float(amount)) } - public func multipliedBy(amount: UInt) -> Constraint { + func multipliedBy(amount: UInt) -> ConstraintPriortizable { return self.multipliedBy(Float(amount)) } - public func dividedBy(amount: Float) -> Constraint { + func dividedBy(amount: Float) -> ConstraintPriortizable { self.multiplier = 1.0 / amount; return self } - public func dividedBy(amount: Double) -> Constraint { + func dividedBy(amount: Double) -> ConstraintPriortizable { return self.dividedBy(Float(amount)) } - public func dividedBy(amount: CGFloat) -> Constraint { + func dividedBy(amount: CGFloat) -> ConstraintPriortizable { return self.dividedBy(Float(amount)) } - public func dividedBy(amount: Int) -> Constraint { + func dividedBy(amount: Int) -> ConstraintPriortizable { return self.dividedBy(Float(amount)) } - public func dividedBy(amount: UInt) -> Constraint { + func dividedBy(amount: UInt) -> ConstraintPriortizable { return self.dividedBy(Float(amount)) } // MARK: priority - public func priority(priority: Float) -> Constraint { + func priority(priority: Float) -> ConstraintFinalizable { self.priority = priority return self } - public func priority(priority: Double) -> Constraint { + func priority(priority: Double) -> ConstraintFinalizable { return self.priority(Float(priority)) } - public func priority(priority: CGFloat) -> Constraint { + func priority(priority: CGFloat) -> ConstraintFinalizable { return self.priority(Float(priority)) } - public func priority(priority: UInt) -> Constraint { + func priority(priority: UInt) -> ConstraintFinalizable { return self.priority(Float(priority)) } - public func priority(priority: Int) -> Constraint { + func priority(priority: Int) -> ConstraintFinalizable { return self.priority(Float(priority)) } - public func priorityRequired() -> Constraint { + func priorityRequired() -> ConstraintFinalizable { return self.priority(1000.0) } - public func priorityHigh() -> Constraint { + func priorityHigh() -> ConstraintFinalizable { return self.priority(750.0) } - public func priorityMedium() -> Constraint { + func priorityMedium() -> ConstraintFinalizable { #if os(iOS) return self.priority(500.0) #else return self.priority(501.0) #endif } - public func priorityLow() -> Constraint { + func priorityLow() -> ConstraintFinalizable { return self.priority(250.0) } // MARK: offset - public func offset(amount: Float) -> Constraint { + func offset(amount: Float) -> ConstraintMultipliable { self.offset = amount return self } - public func offset(amount: Double) -> Constraint { + func offset(amount: Double) -> ConstraintMultipliable { return self.offset(Float(amount)) } - public func offset(amount: CGFloat) -> Constraint { + func offset(amount: CGFloat) -> ConstraintMultipliable { return self.offset(Float(amount)) } - public func offset(amount: Int) -> Constraint { + func offset(amount: Int) -> ConstraintMultipliable { return self.offset(Float(amount)) } - public func offset(amount: UInt) -> Constraint { + func offset(amount: UInt) -> ConstraintMultipliable { return self.offset(Float(amount)) } - public func offset(amount: CGPoint) -> Constraint { + func offset(amount: CGPoint) -> ConstraintMultipliable { self.offset = amount return self } - public func offset(amount: CGSize) -> Constraint { + func offset(amount: CGSize) -> ConstraintMultipliable { self.offset = amount return self } - public func offset(amount: EdgeInsets) -> Constraint { + func offset(amount: EdgeInsets) -> ConstraintMultipliable { self.offset = amount return self } // MARK: insets - public func insets(amount: EdgeInsets) -> Constraint { + func insets(amount: EdgeInsets) -> ConstraintMultipliable { self.offset = amount return self } + // MARK: Constraint + + var constraint: Constraint { + return self + } + // MARK: install / uninstall - public func install() -> [LayoutConstraint] { + func install() -> [LayoutConstraint] { return self.installOnView(updateExisting: false) } - public func uninstall() { + func uninstall() { self.uninstallFromView() } - public func activate() { + func activate() { if NSLayoutConstraint.respondsToSelector("activateConstraints:") && self.installInfo != nil { let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint] if layoutConstraints.count > 0 { @@ -302,7 +462,7 @@ final public class Constraint { } } - public func deactivate() { + func deactivate() { if NSLayoutConstraint.respondsToSelector("deactivateConstraints:") && self.installInfo != nil { let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint] if layoutConstraints.count > 0 { @@ -313,12 +473,10 @@ final public class Constraint { } } - // MARK: internal - - internal func installOnView(updateExisting: Bool = false) -> [LayoutConstraint] { + func installOnView(updateExisting: Bool = false) -> [LayoutConstraint] { var installOnView: View? = nil if self.toItem.view != nil { - installOnView = Constraint.closestCommonSuperviewFromView(self.fromItem.view, toView: self.toItem.view) + installOnView = MutableConstraint.closestCommonSuperviewFromView(self.fromItem.view, toView: self.toItem.view) if installOnView == nil { NSException(name: "Cannot Install Constraint", reason: "No common superview between views", userInfo: nil).raise() return [] @@ -441,7 +599,7 @@ final public class Constraint { return newLayoutConstraints } - internal func uninstallFromView() { + func uninstallFromView() { if let installInfo = self.installInfo, let installedLayoutConstraints = installInfo.layoutConstraints.allObjects as? [LayoutConstraint] { @@ -476,14 +634,14 @@ final public class Constraint { private var installInfo: ConstraintInstallInfo? - private func addConstraint(attributes: ConstraintAttributes) -> Constraint { + private func addConstraint(attributes: ConstraintAttributes) -> MutableConstraint { if self.relation == nil { self.fromItem.attributes += attributes } return self } - private func constrainTo(other: ConstraintItem, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: ConstraintItem, relation: ConstraintRelation) -> MutableConstraint { if other.attributes != ConstraintAttributes.None { let toLayoutAttributes = other.attributes.layoutAttributes if toLayoutAttributes.count > 1 { @@ -499,31 +657,31 @@ final public class Constraint { self.relation = relation return self } - private func constrainTo(other: View, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: View, relation: ConstraintRelation) -> MutableConstraint { return constrainTo(ConstraintItem(object: other, attributes: ConstraintAttributes.None), relation: relation) } #if os(iOS) - private func constrainTo(other: UILayoutSupport, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: UILayoutSupport, relation: ConstraintRelation) -> MutableConstraint { return constrainTo(ConstraintItem(object: other, attributes: ConstraintAttributes.None), relation: relation) } #endif - private func constrainTo(other: Float, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: Float, relation: ConstraintRelation) -> MutableConstraint { self.constant = other return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) } - private func constrainTo(other: Double, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: Double, relation: ConstraintRelation) -> MutableConstraint { self.constant = other return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) } - private func constrainTo(other: CGSize, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: CGSize, relation: ConstraintRelation) -> MutableConstraint { self.constant = other return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) } - private func constrainTo(other: CGPoint, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: CGPoint, relation: ConstraintRelation) -> MutableConstraint { self.constant = other return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) } - private func constrainTo(other: EdgeInsets, relation: ConstraintRelation) -> Constraint { + private func constrainTo(other: EdgeInsets, relation: ConstraintRelation) -> MutableConstraint { self.constant = other return constrainTo(ConstraintItem(object: nil, attributes: ConstraintAttributes.None), relation: relation) } @@ -726,7 +884,7 @@ private struct ConstraintInstallInfo { } -internal func ==(left: Constraint, right: Constraint) -> Bool { +internal func ==(left: MutableConstraint, right: MutableConstraint) -> Bool { return (left.fromItem == right.fromItem && left.toItem == right.toItem && left.relation == right.relation && diff --git a/Source/ConstraintMaker.swift b/Source/ConstraintMaker.swift index f713e70..fa6a5e1 100644 --- a/Source/ConstraintMaker.swift +++ b/Source/ConstraintMaker.swift @@ -31,49 +31,49 @@ import AppKit * ConstraintMaker is the maker in snap that gets all constraints kickstarted */ final public class ConstraintMaker { - public var left: Constraint { return self.addConstraint(ConstraintAttributes.Left) } - public var top: Constraint { return self.addConstraint(ConstraintAttributes.Top) } - public var right: Constraint { return self.addConstraint(ConstraintAttributes.Right) } - public var bottom: Constraint { return self.addConstraint(ConstraintAttributes.Bottom) } - public var leading: Constraint { return self.addConstraint(ConstraintAttributes.Leading) } - public var trailing: Constraint { return self.addConstraint(ConstraintAttributes.Trailing) } - public var width: Constraint { return self.addConstraint(ConstraintAttributes.Width) } - public var height: Constraint { return self.addConstraint(ConstraintAttributes.Height) } - public var centerX: Constraint { return self.addConstraint(ConstraintAttributes.CenterX) } - public var centerY: Constraint { return self.addConstraint(ConstraintAttributes.CenterY) } - public var baseline: Constraint { return self.addConstraint(ConstraintAttributes.Baseline) } + public var left: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Left) } + public var top: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Top) } + public var right: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Right) } + public var bottom: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Bottom) } + public var leading: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Leading) } + public var trailing: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Trailing) } + public var width: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Width) } + public var height: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Height) } + public var centerX: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterX) } + public var centerY: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterY) } + public var baseline: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Baseline) } #if os(iOS) - public var firstBaseline: Constraint { return self.addConstraint(ConstraintAttributes.FirstBaseline) } - public var leftMargin: Constraint { return self.addConstraint(ConstraintAttributes.LeftMargin) } - public var rightMargin: Constraint { return self.addConstraint(ConstraintAttributes.RightMargin) } - public var topMargin: Constraint { return self.addConstraint(ConstraintAttributes.TopMargin) } - public var bottomMargin: Constraint { return self.addConstraint(ConstraintAttributes.BottomMargin) } - public var leadingMargin: Constraint { return self.addConstraint(ConstraintAttributes.LeadingMargin) } - public var trailingMargin: Constraint { return self.addConstraint(ConstraintAttributes.TrailingMargin) } - public var centerXWithinMargins: Constraint { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } - public var centerYWithinMargins: Constraint { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } + public var firstBaseline: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.FirstBaseline) } + public var leftMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.LeftMargin) } + public var rightMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.RightMargin) } + public var topMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.TopMargin) } + public var bottomMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.BottomMargin) } + public var leadingMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.LeadingMargin) } + public var trailingMargin: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.TrailingMargin) } + public var centerXWithinMargins: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterXWithinMargins) } + public var centerYWithinMargins: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.CenterYWithinMargins) } #endif - public var edges: Constraint { return self.addConstraint(ConstraintAttributes.Edges) } - public var size: Constraint { return self.addConstraint(ConstraintAttributes.Size) } - public var center: Constraint { return self.addConstraint(ConstraintAttributes.Center) } + public var edges: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Edges) } + public var size: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Size) } + public var center: ConstraintExtendable { return self.addConstraint(ConstraintAttributes.Center) } init(view: View) { self.view = view } internal weak var view: View? - internal var constraints = [Constraint]() + internal var constraints = [MutableConstraint]() - internal func addConstraint(attributes: ConstraintAttributes) -> Constraint { + internal func addConstraint(attributes: ConstraintAttributes) -> MutableConstraint { let item = ConstraintItem(object: self.view, attributes: attributes) - let constraint = Constraint(fromItem: item) + let constraint = MutableConstraint(fromItem: item) self.constraints.append(constraint) return constraint } - internal class func prepareConstraints(view: View, @noescape block: (make: ConstraintMaker) -> Void) -> [Constraint] { + internal class func prepareConstraints(view: View, @noescape block: (make: ConstraintMaker) -> Void) -> [MutableConstraint] { let maker = ConstraintMaker(view: view) block(make: maker) return maker.constraints diff --git a/Source/LayoutConstraint.swift b/Source/LayoutConstraint.swift index 6f78022..a05d1ba 100644 --- a/Source/LayoutConstraint.swift +++ b/Source/LayoutConstraint.swift @@ -31,7 +31,7 @@ import AppKit * LayoutConstraint is a subclass of NSLayoutConstraint to assist Snap and also provide better debugging */ final public class LayoutConstraint: NSLayoutConstraint { - internal var snp_constraint: Constraint? = nil + internal var snp_constraint: MutableConstraint? = nil } public func ==(left: LayoutConstraint, right: LayoutConstraint) -> Bool { diff --git a/Source/View+Snap.swift b/Source/View+Snap.swift index 5d7c1f8..5279616 100644 --- a/Source/View+Snap.swift +++ b/Source/View+Snap.swift @@ -72,7 +72,7 @@ public extension View { #endif final public func snp_prepareConstraints(@noescape block: (make: ConstraintMaker) -> Void) -> [Constraint] { - return ConstraintMaker.prepareConstraints(self, block: block) + return ConstraintMaker.prepareConstraints(self, block: block).map { return $0 as Constraint } } final public func snp_makeConstraints(@noescape block: (make: ConstraintMaker) -> Void) { diff --git a/Tests/Tests.swift b/Tests/Tests.swift index bc9eac7..3e7d571 100644 --- a/Tests/Tests.swift +++ b/Tests/Tests.swift @@ -181,8 +181,8 @@ class SnapTests: XCTestCase { var c2: Constraint? = nil v1.snp_prepareConstraints { (make) -> Void in - c1 = make.top.equalTo(v2.snp_top).offset(50) - c2 = make.left.equalTo(v2.snp_top).offset(50) + c1 = make.top.equalTo(v2.snp_top).offset(50).constraint + c2 = make.left.equalTo(v2.snp_top).offset(50).constraint return }