2014-07-25 12:24:17 +08:00
//
2015-04-15 19:07:50 +08:00
// S n a p K i t
2014-07-25 12:24:17 +08:00
//
2015-04-15 19:07:50 +08:00
// C o p y r i g h t ( c ) 2 0 1 1 - P r e s e n t S n a p K i t T e a m - h t t p s : / / g i t h u b . c o m / S n a p K i t
2014-07-25 12:24:17 +08:00
//
2014-07-29 08:39:59 +08:00
// P e r m i s s i o n i s h e r e b y g r a n t e d , f r e e o f c h a r g e , t o a n y p e r s o n o b t a i n i n g a c o p y
// o f t h i s s o f t w a r e a n d a s s o c i a t e d d o c u m e n t a t i o n f i l e s ( t h e " S o f t w a r e " ) , t o d e a l
// i n t h e S o f t w a r e w i t h o u t r e s t r i c t i o n , i n c l u d i n g w i t h o u t l i m i t a t i o n t h e r i g h t s
// t o u s e , c o p y , m o d i f y , m e r g e , p u b l i s h , d i s t r i b u t e , s u b l i c e n s e , a n d / o r s e l l
// c o p i e s o f t h e S o f t w a r e , a n d t o p e r m i t p e r s o n s t o w h o m t h e S o f t w a r e i s
// f u r n i s h e d t o d o s o , s u b j e c t t o t h e f o l l o w i n g c o n d i t i o n s :
//
// T h e a b o v e c o p y r i g h t n o t i c e a n d t h i s p e r m i s s i o n n o t i c e s h a l l b e i n c l u d e d i n
// a l l c o p i e s o r s u b s t a n t i a l p o r t i o n s o f t h e S o f t w a r e .
//
// T H E S O F T W A R E I S P R O V I D E D " A S I S " , W I T H O U T W A R R A N T Y O F A N Y K I N D , E X P R E S S O R
// I M P L I E D , I N C L U D I N G B U T N O T L I M I T E D T O T H E W A R R A N T I E S O F M E R C H A N T A B I L I T Y ,
// F I T N E S S F O R A P A R T I C U L A R P U R P O S E A N D N O N I N F R I N G E M E N T . I N N O E V E N T S H A L L T H E
// A U T H O R S O R C O P Y R I G H T H O L D E R S B E L I A B L E F O R A N Y C L A I M , D A M A G E S O R O T H E R
// L I A B I L I T Y , W H E T H E R I N A N A C T I O N O F C O N T R A C T , T O R T O R O T H E R W I S E , A R I S I N G F R O M ,
// O U T O F O R I N C O N N E C T I O N W I T H T H E S O F T W A R E O R T H E U S E O R O T H E R D E A L I N G S I N
// T H E S O F T W A R E .
2014-07-25 12:24:17 +08:00
2015-09-25 12:37:33 +08:00
#if os ( iOS ) || os ( tvOS )
2014-07-25 12:24:17 +08:00
import UIKit
2014-07-30 08:55:31 +08:00
#else
import AppKit
#endif
2014-07-25 12:24:17 +08:00
2015-04-12 19:32:03 +08:00
/* *
Used to expose API ' s for a Constraint
*/
2015-04-15 19:31:03 +08:00
public class Constraint {
2015-04-11 19:39:12 +08:00
2015-04-15 19:31:03 +08:00
public func install ( ) -> [ LayoutConstraint ] { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func uninstall ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func activate ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func deactivate ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
2015-04-12 19:32:03 +08:00
2015-04-15 19:31:03 +08:00
public func updateOffset ( amount : Float ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : Double ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : CGFloat ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : Int ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : UInt ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : CGPoint ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : CGSize ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updateOffset ( amount : EdgeInsets ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
2015-04-12 19:32:03 +08:00
2015-04-15 19:31:03 +08:00
public func updateInsets ( amount : EdgeInsets ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
2015-04-12 19:32:03 +08:00
2015-04-15 19:31:03 +08:00
public func updatePriority ( priority : Float ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriority ( priority : Double ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriority ( priority : CGFloat ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriority ( priority : UInt ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriority ( priority : Int ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriorityRequired ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriorityHigh ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriorityMedium ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
public func updatePriorityLow ( ) -> Void { fatalError ( " Must be implemented by Concrete subclass. " ) }
2015-04-12 19:32:03 +08:00
2015-07-30 14:49:47 +08:00
internal var makerFile : String = " Unknown "
internal var makerLine : UInt = 0
2015-04-12 19:32:03 +08:00
}
/* *
Used internally to implement a ConcreteConstraint
*/
2015-04-22 20:31:40 +08:00
internal class ConcreteConstraint : Constraint {
2015-04-12 19:32:03 +08:00
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : Float ) -> Void {
2015-04-12 19:32:03 +08:00
self . constant = amount
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : Double ) -> Void {
2015-04-12 19:32:03 +08:00
self . updateOffset ( Float ( amount ) )
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : CGFloat ) -> Void {
2015-04-12 19:32:03 +08:00
self . updateOffset ( Float ( amount ) )
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : Int ) -> Void {
2015-04-12 19:32:03 +08:00
self . updateOffset ( Float ( amount ) )
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : UInt ) -> Void {
2015-04-12 19:32:03 +08:00
self . updateOffset ( Float ( amount ) )
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : CGPoint ) -> Void {
2015-04-12 19:32:03 +08:00
self . constant = amount
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : CGSize ) -> Void {
2015-04-12 19:32:03 +08:00
self . constant = amount
}
2015-04-15 19:31:03 +08:00
internal override func updateOffset ( amount : EdgeInsets ) -> Void {
2015-04-12 19:32:03 +08:00
self . constant = amount
}
2015-04-15 19:31:03 +08:00
internal override func updateInsets ( amount : EdgeInsets ) -> Void {
2015-04-12 19:32:03 +08:00
self . constant = EdgeInsets ( top : amount . top , left : amount . left , bottom : - amount . bottom , right : - amount . right )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriority ( priority : Float ) -> Void {
2015-04-12 19:32:03 +08:00
self . priority = priority
}
2015-04-15 19:31:03 +08:00
internal override func updatePriority ( priority : Double ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( priority ) )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriority ( priority : CGFloat ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( priority ) )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriority ( priority : UInt ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( priority ) )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriority ( priority : Int ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( priority ) )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriorityRequired ( ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( 1000.0 ) )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriorityHigh ( ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( 750.0 ) )
}
2015-04-15 19:31:03 +08:00
internal override func updatePriorityMedium ( ) -> Void {
2015-09-25 12:37:33 +08:00
#if os ( iOS ) || os ( tvOS )
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( 500.0 ) )
#else
self . updatePriority ( Float ( 501.0 ) )
#endif
}
2015-04-15 19:31:03 +08:00
internal override func updatePriorityLow ( ) -> Void {
2015-04-12 19:32:03 +08:00
self . updatePriority ( Float ( 250.0 ) )
}
2015-04-15 19:31:03 +08:00
internal override func install ( ) -> [ LayoutConstraint ] {
2015-07-30 15:35:48 +08:00
return self . installOnView ( updateExisting : false , file : self . makerFile , line : self . makerLine )
2015-04-12 18:21:02 +08:00
}
2015-04-15 19:31:03 +08:00
internal override func uninstall ( ) -> Void {
2015-04-12 18:21:02 +08:00
self . uninstallFromView ( )
}
2015-04-15 19:31:03 +08:00
internal override func activate ( ) -> Void {
2015-09-22 15:38:50 +08:00
guard self . installInfo != nil else {
2015-04-12 18:21:02 +08:00
self . install ( )
2015-09-18 12:18:28 +08:00
return
}
2015-09-22 15:38:50 +08:00
#if SNAPKIT_DEPLOYMENT_LEGACY
guard #available ( iOS 8.0 , OSX 10.10 , * ) else {
self . install ( )
return
}
#endif
2015-09-18 12:18:28 +08:00
let layoutConstraints = self . installInfo ! . layoutConstraints . allObjects as ! [ LayoutConstraint ]
if layoutConstraints . count > 0 {
NSLayoutConstraint . activateConstraints ( layoutConstraints )
2015-04-12 18:21:02 +08:00
}
}
2015-04-15 19:31:03 +08:00
internal override func deactivate ( ) -> Void {
2015-09-22 15:38:50 +08:00
guard self . installInfo != nil else {
return
}
#if SNAPKIT_DEPLOYMENT_LEGACY
guard #available ( iOS 8.0 , OSX 10.10 , * ) else {
2015-09-18 12:18:28 +08:00
return
}
2015-09-22 15:38:50 +08:00
#endif
2015-09-18 12:18:28 +08:00
let layoutConstraints = self . installInfo ! . layoutConstraints . allObjects as ! [ LayoutConstraint ]
if layoutConstraints . count > 0 {
NSLayoutConstraint . deactivateConstraints ( layoutConstraints )
2015-04-12 18:21:02 +08:00
}
}
private let fromItem : ConstraintItem
private let toItem : ConstraintItem
private let relation : ConstraintRelation
2015-04-12 19:32:03 +08:00
private let multiplier : Float
private var constant : Any {
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
}
}
}
}
2015-04-12 18:21:02 +08:00
2015-04-12 19:32:03 +08:00
private var installInfo : ConcreteConstraintInstallInfo ? = nil
2015-04-12 18:21:02 +08:00
internal init ( fromItem : ConstraintItem , toItem : ConstraintItem , relation : ConstraintRelation , constant : Any , multiplier : Float , priority : Float ) {
self . fromItem = fromItem
self . toItem = toItem
self . relation = relation
self . constant = constant
self . multiplier = multiplier
self . priority = priority
}
2015-07-30 15:35:48 +08:00
internal func installOnView ( updateExisting updateExisting : Bool = false , file : String ? = nil , line : UInt ? = nil ) -> [ LayoutConstraint ] {
2015-04-12 18:21:02 +08:00
var installOnView : View ? = nil
if self . toItem . view != nil {
2015-06-17 19:09:54 +08:00
installOnView = closestCommonSuperviewFromView ( self . fromItem . view , toView : self . toItem . view )
2015-04-12 18:21:02 +08:00
if installOnView = = nil {
2015-07-30 14:49:47 +08:00
NSException ( name : " Cannot Install Constraint " , reason : " No common superview between views (@ \( self . makerFile ) # \( self . makerLine ) ) " , userInfo : nil ) . raise ( )
2015-04-12 18:21:02 +08:00
return [ ]
}
} else {
2015-07-30 14:49:47 +08:00
2015-07-30 15:35:48 +08:00
if self . fromItem . attributes . isSubsetOf ( ConstraintAttributes . Width . union ( . Height ) ) {
2015-07-30 14:49:47 +08:00
installOnView = self . fromItem . view
} else {
installOnView = self . fromItem . view ? . superview
2015-04-12 18:21:02 +08:00
if installOnView = = nil {
2015-07-30 14:49:47 +08:00
NSException ( name : " Cannot Install Constraint " , reason : " Missing superview (@ \( self . makerFile ) # \( self . makerLine ) ) " , userInfo : nil ) . raise ( )
2015-04-12 18:21:02 +08:00
return [ ]
}
}
}
if let installedOnView = self . installInfo ? . view {
if installedOnView != installOnView {
2015-07-30 14:49:47 +08:00
NSException ( name : " Cannot Install Constraint " , reason : " Already installed on different view. (@ \( self . makerFile ) # \( self . makerLine ) ) " , userInfo : nil ) . raise ( )
2015-04-12 18:21:02 +08:00
return [ ]
}
return self . installInfo ? . layoutConstraints . allObjects as ? [ LayoutConstraint ] ? ? [ ]
}
var newLayoutConstraints = [ LayoutConstraint ] ( )
let layoutFromAttributes = self . fromItem . attributes . layoutAttributes
let layoutToAttributes = self . toItem . attributes . layoutAttributes
// g e t l a y o u t f r o m
let layoutFrom : View ? = self . fromItem . view
// g e t l a y o u t r e l a t i o n
let layoutRelation : NSLayoutRelation = self . relation . layoutRelation
for layoutFromAttribute in layoutFromAttributes {
// g e t l a y o u t t o a t t r i b u t e
let layoutToAttribute = ( layoutToAttributes . count > 0 ) ? layoutToAttributes [ 0 ] : layoutFromAttribute
// g e t l a y o u t c o n s t a n t
2015-06-17 19:09:54 +08:00
let layoutConstant : CGFloat = layoutToAttribute . snp_constantForValue ( self . constant )
2015-04-12 18:21:02 +08:00
// g e t l a y o u t t o
2015-09-25 12:37:33 +08:00
#if os ( iOS ) || os ( tvOS )
2015-09-22 15:38:50 +08:00
var layoutTo : AnyObject ? = self . toItem . view ? ? self . toItem . layoutSupport
#else
var layoutTo : AnyObject ? = self . toItem . view
#endif
2015-04-12 18:21:02 +08:00
if layoutTo = = nil && layoutToAttribute != . Width && layoutToAttribute != . Height {
layoutTo = installOnView
}
// c r e a t e l a y o u t c o n s t r a i n t
let layoutConstraint = LayoutConstraint (
item : layoutFrom ! ,
attribute : layoutFromAttribute ,
relatedBy : layoutRelation ,
toItem : layoutTo ,
attribute : layoutToAttribute ,
multiplier : CGFloat ( self . multiplier ) ,
constant : layoutConstant )
// s e t p r i o r i t y
layoutConstraint . priority = self . priority
// s e t c o n s t r a i n t
layoutConstraint . snp_constraint = self
newLayoutConstraints . append ( layoutConstraint )
}
// s p e c i a l l o g i c f o r u p d a t i n g
if updateExisting {
// g e t e x i s t i n g c o n s t r a i n t s f o r t h i s v i e w
2015-06-17 19:09:54 +08:00
let existingLayoutConstraints = layoutFrom ! . snp_installedLayoutConstraints . reverse ( )
2015-04-12 18:21:02 +08:00
// a r r a y t h a t w i l l c o n t a i n o n l y n e w l a y o u t c o n s t r a i n t s t o k e e p
var newLayoutConstraintsToKeep = [ LayoutConstraint ] ( )
// b e g i n l o o p i n g
for layoutConstraint in newLayoutConstraints {
// l a y o u t c o n s t r a i n t t h a t s h o u l d b e u p d a t e d
var updateLayoutConstraint : LayoutConstraint ? = nil
// l o o p t h r o u g h e x i s t i n g a n d c h e c k f o r m a t c h
for existingLayoutConstraint in existingLayoutConstraints {
if existingLayoutConstraint = = layoutConstraint {
updateLayoutConstraint = existingLayoutConstraint
break
}
}
// i f w e h a v e e x i s t i n g o n e l e t s j u s t u p d a t e t h e c o n s t a n t
if updateLayoutConstraint != nil {
updateLayoutConstraint ! . constant = layoutConstraint . constant
}
// o t h e r w i s e a d d t h i s l a y o u t c o n s t r a i n t t o n e w k e e p l i s t
else {
newLayoutConstraintsToKeep . append ( layoutConstraint )
}
}
// s e t c o n s t r a i n t s t o o n l y n e w o n e s
newLayoutConstraints = newLayoutConstraintsToKeep
}
// a d d c o n s t r a i n t s
installOnView ! . addConstraints ( newLayoutConstraints )
// s e t i n s t a l l i n f o
2015-04-12 19:32:03 +08:00
self . installInfo = ConcreteConstraintInstallInfo ( view : installOnView , layoutConstraints : NSHashTable . weakObjectsHashTable ( ) )
2015-04-12 18:21:02 +08:00
// s t o r e w h i c h l a y o u t c o n s t r a i n t s a r e i n s t a l l e d f o r t h i s c o n s t r a i n t
for layoutConstraint in newLayoutConstraints {
self . installInfo ! . layoutConstraints . addObject ( layoutConstraint )
}
// s t o r e t h e l a y o u t c o n s t r a i n t s a g a i n s t t h e l a y o u t f r o m v i e w
layoutFrom ! . snp_installedLayoutConstraints += newLayoutConstraints
// r e t u r n t h e n e w c o n s t r a i n t s
return newLayoutConstraints
}
internal func uninstallFromView ( ) {
if let installInfo = self . installInfo ,
let installedLayoutConstraints = installInfo . layoutConstraints . allObjects as ? [ LayoutConstraint ] {
if installedLayoutConstraints . count > 0 {
if let installedOnView = installInfo . view {
// r e m o v e t h e c o n s t r a i n t s f r o m t h e U I V i e w ' s s t o r a g e
installedOnView . removeConstraints ( installedLayoutConstraints )
}
// r e m o v e t h e c o n s t r a i n t s f r o m t h e f r o m i t e m v i e w
if let fromView = self . fromItem . view {
fromView . snp_installedLayoutConstraints = fromView . snp_installedLayoutConstraints . filter {
2015-06-17 19:09:54 +08:00
return ! installedLayoutConstraints . contains ( $0 )
2015-04-12 18:21:02 +08:00
}
}
}
}
self . installInfo = nil
}
2015-04-11 19:39:12 +08:00
}
2015-04-12 18:21:02 +08:00
2015-04-12 19:32:03 +08:00
private struct ConcreteConstraintInstallInfo {
2015-04-12 18:21:02 +08:00
weak var view : View ? = nil
let layoutConstraints : NSHashTable
}
private extension NSLayoutAttribute {
private func snp_constantForValue ( value : Any ? ) -> CGFloat {
// F l o a t
if let float = value as ? Float {
return CGFloat ( float )
}
// D o u b l e
else if let double = value as ? Double {
return CGFloat ( double )
}
// U I n t
else if let int = value as ? Int {
return CGFloat ( int )
}
// I n t
else if let uint = value as ? UInt {
return CGFloat ( uint )
}
// C G F l o a t
else if let float = value as ? CGFloat {
return float
}
// C G S i z e
else if let size = value as ? CGSize {
if self = = . Width {
return size . width
} else if self = = . Height {
return size . height
}
}
// C G P o i n t
else if let point = value as ? CGPoint {
2015-09-25 12:37:33 +08:00
#if os ( iOS ) || os ( tvOS )
2015-04-12 18:21:02 +08:00
switch self {
case . Left , . CenterX , . LeftMargin , . CenterXWithinMargins : return point . x
case . Top , . CenterY , . TopMargin , . CenterYWithinMargins , . Baseline , . FirstBaseline : return point . y
case . Right , . RightMargin : return point . x
case . Bottom , . BottomMargin : return point . y
case . Leading , . LeadingMargin : return point . x
case . Trailing , . TrailingMargin : return point . x
case . Width , . Height , . NotAnAttribute : return CGFloat ( 0 )
}
2015-04-15 19:17:20 +08:00
#else
2015-04-12 18:21:02 +08:00
switch self {
case . Left , . CenterX : return point . x
case . Top , . CenterY , . Baseline : return point . y
case . Right : return point . x
case . Bottom : return point . y
case . Leading : return point . x
case . Trailing : return point . x
case . Width , . Height , . NotAnAttribute : return CGFloat ( 0 )
2015-06-25 06:10:38 +08:00
case . FirstBaseline : return point . y
2015-04-12 18:21:02 +08:00
}
#endif
}
// E d g e I n s e t s
else if let insets = value as ? EdgeInsets {
2015-09-25 12:37:33 +08:00
#if os ( iOS ) || os ( tvOS )
2015-04-12 18:21:02 +08:00
switch self {
case . Left , . CenterX , . LeftMargin , . CenterXWithinMargins : return insets . left
case . Top , . CenterY , . TopMargin , . CenterYWithinMargins , . Baseline , . FirstBaseline : return insets . top
case . Right , . RightMargin : return insets . right
case . Bottom , . BottomMargin : return insets . bottom
case . Leading , . LeadingMargin : return ( Config . interfaceLayoutDirection = = . LeftToRight ) ? insets . left : - insets . right
case . Trailing , . TrailingMargin : return ( Config . interfaceLayoutDirection = = . LeftToRight ) ? insets . right : - insets . left
case . Width , . Height , . NotAnAttribute : return CGFloat ( 0 )
}
2015-04-15 19:17:20 +08:00
#else
2015-04-12 18:21:02 +08:00
switch self {
case . Left , . CenterX : return insets . left
case . Top , . CenterY , . Baseline : return insets . top
case . Right : return insets . right
case . Bottom : return insets . bottom
2015-04-15 19:17:20 +08:00
case . Leading : return ( Config . interfaceLayoutDirection = = . LeftToRight ) ? insets . left : - insets . right
case . Trailing : return ( Config . interfaceLayoutDirection = = . LeftToRight ) ? insets . right : - insets . left
2015-04-12 18:21:02 +08:00
case . Width , . Height , . NotAnAttribute : return CGFloat ( 0 )
2015-06-25 06:10:38 +08:00
case . FirstBaseline : return insets . bottom
2015-04-12 18:21:02 +08:00
}
#endif
}
return CGFloat ( 0 ) ;
}
}
2015-06-17 19:09:54 +08:00
private func closestCommonSuperviewFromView ( fromView : View ? , toView : View ? ) -> View ? {
2015-04-12 18:21:02 +08:00
var views = Set < View > ( )
var fromView = fromView
var toView = toView
2015-06-17 19:09:54 +08:00
repeat {
2015-04-12 18:21:02 +08:00
if let view = toView {
if views . contains ( view ) {
return view
}
views . insert ( view )
toView = view . superview
}
if let view = fromView {
if views . contains ( view ) {
return view
}
views . insert ( view )
fromView = view . superview
}
} while ( fromView != nil || toView != nil )
return nil
}
2015-04-12 19:32:03 +08:00
private func = = ( left : ConcreteConstraint , right : ConcreteConstraint ) -> Bool {
2015-04-12 18:21:02 +08:00
return ( left . fromItem = = right . fromItem &&
left . toItem = = right . toItem &&
left . relation = = right . relation &&
left . multiplier = = right . multiplier &&
left . priority = = right . priority )
2015-06-17 19:09:54 +08:00
}