Refactor Constraint -> ConcreteConstraint & Add Updaters!

This commit is contained in:
Robert Payne 2015-04-12 23:32:03 +12:00
parent 73e038f3ab
commit 2b00e7b50c
3 changed files with 141 additions and 36 deletions

View File

@ -27,17 +27,114 @@ import UIKit
import AppKit import AppKit
#endif #endif
public class Constraint { /**
Used to expose API's for a Constraint
*/
public protocol Constraint: class {
public func install() -> [LayoutConstraint] { func install() -> [LayoutConstraint]
func uninstall()
func activate()
func deactivate()
func updateOffset(amount: Float) -> Void
func updateOffset(amount: Double) -> Void
func updateOffset(amount: CGFloat) -> Void
func updateOffset(amount: Int) -> Void
func updateOffset(amount: UInt) -> Void
func updateOffset(amount: CGPoint) -> Void
func updateOffset(amount: CGSize) -> Void
func updateOffset(amount: EdgeInsets) -> Void
func updateInsets(amount: EdgeInsets) -> Void
func updatePriority(priority: Float) -> Void
func updatePriority(priority: Double) -> Void
func updatePriority(priority: CGFloat) -> Void
func updatePriority(priority: UInt) -> Void
func updatePriority(priority: Int) -> Void
func updatePriorityRequired() -> Void
func updatePriorityHigh() -> Void
func updatePriorityMedium() -> Void
func updatePriorityLow() -> Void
}
/**
Used internally to implement a ConcreteConstraint
*/
internal class ConcreteConstraint: Constraint {
internal func updateOffset(amount: Float) -> Void {
self.constant = amount
}
internal func updateOffset(amount: Double) -> Void {
self.updateOffset(Float(amount))
}
internal func updateOffset(amount: CGFloat) -> Void {
self.updateOffset(Float(amount))
}
internal func updateOffset(amount: Int) -> Void {
self.updateOffset(Float(amount))
}
internal func updateOffset(amount: UInt) -> Void {
self.updateOffset(Float(amount))
}
internal func updateOffset(amount: CGPoint) -> Void {
self.constant = amount
}
internal func updateOffset(amount: CGSize) -> Void {
self.constant = amount
}
internal func updateOffset(amount: EdgeInsets) -> Void {
self.constant = amount
}
internal func updateInsets(amount: EdgeInsets) -> Void {
self.constant = EdgeInsets(top: amount.top, left: amount.left, bottom: -amount.bottom, right: -amount.right)
}
internal func updatePriority(priority: Float) -> Void {
self.priority = priority
}
internal func updatePriority(priority: Double) -> Void {
self.updatePriority(Float(priority))
}
internal func updatePriority(priority: CGFloat) -> Void {
self.updatePriority(Float(priority))
}
internal func updatePriority(priority: UInt) -> Void {
self.updatePriority(Float(priority))
}
internal func updatePriority(priority: Int) -> Void {
self.updatePriority(Float(priority))
}
internal func updatePriorityRequired() -> Void {
self.updatePriority(Float(1000.0))
}
internal func updatePriorityHigh() -> Void {
self.updatePriority(Float(750.0))
}
internal func updatePriorityMedium() -> Void {
#if os(iOS)
self.updatePriority(Float(500.0))
#else
self.updatePriority(Float(501.0))
#endif
}
internal func updatePriorityLow() -> Void {
self.updatePriority(Float(250.0))
}
internal func install() -> [LayoutConstraint] {
return self.installOnView(updateExisting: false) return self.installOnView(updateExisting: false)
} }
public func uninstall() { internal func uninstall() {
self.uninstallFromView() self.uninstallFromView()
} }
public func activate() { internal func activate() {
if NSLayoutConstraint.respondsToSelector("activateConstraints:") && self.installInfo != nil { if NSLayoutConstraint.respondsToSelector("activateConstraints:") && self.installInfo != nil {
let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint] let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint]
if layoutConstraints.count > 0 { if layoutConstraints.count > 0 {
@ -48,7 +145,7 @@ public class Constraint {
} }
} }
public func deactivate() { internal func deactivate() {
if NSLayoutConstraint.respondsToSelector("deactivateConstraints:") && self.installInfo != nil { if NSLayoutConstraint.respondsToSelector("deactivateConstraints:") && self.installInfo != nil {
let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint] let layoutConstraints = self.installInfo!.layoutConstraints.allObjects as! [LayoutConstraint]
if layoutConstraints.count > 0 { if layoutConstraints.count > 0 {
@ -62,11 +159,28 @@ public class Constraint {
private let fromItem: ConstraintItem private let fromItem: ConstraintItem
private let toItem: ConstraintItem private let toItem: ConstraintItem
private let relation: ConstraintRelation private let relation: ConstraintRelation
private var constant: Any private let multiplier: Float
private var multiplier: Float private var constant: Any {
private var priority: Float didSet {
if let installInfo = self.installInfo {
for layoutConstraint in installInfo.layoutConstraints.allObjects as! [LayoutConstraint] {
let attribute = (layoutConstraint.secondAttribute == .NotAnAttribute) ? layoutConstraint.firstAttribute : layoutConstraint.secondAttribute
layoutConstraint.constant = attribute.snp_constantForValue(self.constant)
}
}
}
}
private var priority: Float {
didSet {
if let installInfo = self.installInfo {
for layoutConstraint in installInfo.layoutConstraints.allObjects as! [LayoutConstraint] {
layoutConstraint.priority = self.priority
}
}
}
}
private var installInfo: ConstraintInstallInfo? = nil private var installInfo: ConcreteConstraintInstallInfo? = nil
internal init(fromItem: ConstraintItem, toItem: ConstraintItem, relation: ConstraintRelation, constant: Any, multiplier: Float, priority: Float) { internal init(fromItem: ConstraintItem, toItem: ConstraintItem, relation: ConstraintRelation, constant: Any, multiplier: Float, priority: Float) {
self.fromItem = fromItem self.fromItem = fromItem
@ -188,7 +302,7 @@ public class Constraint {
installOnView!.addConstraints(newLayoutConstraints) installOnView!.addConstraints(newLayoutConstraints)
// set install info // set install info
self.installInfo = ConstraintInstallInfo(view: installOnView, layoutConstraints: NSHashTable.weakObjectsHashTable()) self.installInfo = ConcreteConstraintInstallInfo(view: installOnView, layoutConstraints: NSHashTable.weakObjectsHashTable())
// store which layout constraints are installed for this constraint // store which layout constraints are installed for this constraint
for layoutConstraint in newLayoutConstraints { for layoutConstraint in newLayoutConstraints {
@ -227,7 +341,7 @@ public class Constraint {
} }
private struct ConstraintInstallInfo { private struct ConcreteConstraintInstallInfo {
weak var view: View? = nil weak var view: View? = nil
let layoutConstraints: NSHashTable let layoutConstraints: NSHashTable
@ -342,19 +456,10 @@ private func closestCommonSuperviewBetween(fromView: View?, toView: View?) -> Vi
return nil return nil
} }
private func ==(left: Constraint, right: Constraint) -> Bool { private func ==(left: ConcreteConstraint, right: ConcreteConstraint) -> Bool {
return (left.fromItem == right.fromItem && return (left.fromItem == right.fromItem &&
left.toItem == right.toItem && left.toItem == right.toItem &&
left.relation == right.relation && left.relation == right.relation &&
left.multiplier == right.multiplier && left.multiplier == right.multiplier &&
left.priority == right.priority) left.priority == right.priority)
} }
//public protocol Constraint: class {
//
// func install() -> [LayoutConstraint]
// func uninstall() -> Void
// func activate() -> Void
// func deactivate() -> Void
//
//}

View File

@ -429,11 +429,11 @@ final internal class ConstraintDescription: ConstraintDescriptionExtendable, Con
// MARK: Constraint // MARK: Constraint
internal var constraint: Constraint { internal var constraint: Constraint {
if self.createdConstraint == nil { if self.concreteConstraint == nil {
if self.relation == nil { if self.relation == nil {
fatalError("Attempting to create a constraint from a ConstraintDescription before it has been fully chained.") fatalError("Attempting to create a constraint from a ConstraintDescription before it has been fully chained.")
} }
self.createdConstraint = Constraint( self.concreteConstraint = ConcreteConstraint(
fromItem: self.fromItem, fromItem: self.fromItem,
toItem: self.toItem, toItem: self.toItem,
relation: self.relation!, relation: self.relation!,
@ -441,7 +441,7 @@ final internal class ConstraintDescription: ConstraintDescriptionExtendable, Con
multiplier: self.multiplier, multiplier: self.multiplier,
priority: self.priority) priority: self.priority)
} }
return self.createdConstraint! return self.concreteConstraint!
} }
// MARK: Private // MARK: Private
@ -449,40 +449,40 @@ final internal class ConstraintDescription: ConstraintDescriptionExtendable, Con
private let fromItem: ConstraintItem private let fromItem: ConstraintItem
private var toItem: ConstraintItem { private var toItem: ConstraintItem {
willSet { willSet {
if self.createdConstraint != nil { if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.") fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
} }
} }
} }
private var relation: ConstraintRelation? { private var relation: ConstraintRelation? {
willSet { willSet {
if self.createdConstraint != nil { if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.") fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
} }
} }
} }
private var constant: Any = Float(0.0) { private var constant: Any = Float(0.0) {
willSet { willSet {
if self.createdConstraint != nil { if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.") fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
} }
} }
} }
private var multiplier: Float = 1.0 { private var multiplier: Float = 1.0 {
willSet { willSet {
if self.createdConstraint != nil { if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.") fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
} }
} }
} }
private var priority: Float = 1000.0 { private var priority: Float = 1000.0 {
willSet { willSet {
if self.createdConstraint != nil { if self.concreteConstraint != nil {
fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.") fatalError("Attempting to modify a ConstraintDescription after its constraint has been created.")
} }
} }
} }
private var createdConstraint: Constraint? = nil private var concreteConstraint: ConcreteConstraint? = nil
private func addConstraint(attributes: ConstraintAttributes) -> ConstraintDescription { private func addConstraint(attributes: ConstraintAttributes) -> ConstraintDescription {
if self.relation == nil { if self.relation == nil {

View File

@ -118,7 +118,7 @@ final public class ConstraintMaker {
self.view = view self.view = view
} }
internal weak var view: View? internal let view: View
internal var constraintDescriptions = [ConstraintDescription]() internal var constraintDescriptions = [ConstraintDescription]()
internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescription { internal func makeConstraintDescription(attributes: ConstraintAttributes) -> ConstraintDescription {
@ -144,7 +144,7 @@ final public class ConstraintMaker {
let maker = ConstraintMaker(view: view) let maker = ConstraintMaker(view: view)
closure(make: maker) closure(make: maker)
let constraints = maker.constraintDescriptions.map { $0.constraint } let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
for constraint in constraints { for constraint in constraints {
constraint.installOnView(updateExisting: false) constraint.installOnView(updateExisting: false)
} }
@ -160,7 +160,7 @@ final public class ConstraintMaker {
closure(make: maker) closure(make: maker)
self.removeConstraints(view) self.removeConstraints(view)
let constraints = maker.constraintDescriptions.map { $0.constraint } let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint }
for constraint in constraints { for constraint in constraints {
constraint.installOnView(updateExisting: false) constraint.installOnView(updateExisting: false)
} }
@ -175,7 +175,7 @@ final public class ConstraintMaker {
let maker = ConstraintMaker(view: view) let maker = ConstraintMaker(view: view)
closure(make: maker) closure(make: maker)
let constraints = maker.constraintDescriptions.map { $0.constraint } let constraints = maker.constraintDescriptions.map { $0.constraint as! ConcreteConstraint}
for constraint in constraints { for constraint in constraints {
constraint.installOnView(updateExisting: true) constraint.installOnView(updateExisting: true)
} }
@ -183,7 +183,7 @@ final public class ConstraintMaker {
internal class func removeConstraints(view: View) { internal class func removeConstraints(view: View) {
for existingLayoutConstraint in view.snp_installedLayoutConstraints { for existingLayoutConstraint in view.snp_installedLayoutConstraints {
existingLayoutConstraint.snp_constraint?.uninstallFromView() existingLayoutConstraint.snp_constraint?.uninstall()
} }
} }
} }