├── .gitignore ├── LICENSE ├── Package.swift ├── README.md ├── Sources └── Swiftstraints │ ├── AxisAnchor.swift │ ├── DimensionAnchor.swift │ ├── LayoutPriority.swift │ ├── NSLayoutConstraint+Extensions.swift │ ├── Swiftstraints.h │ ├── UIView+Additions.swift │ ├── VFLComponent.swift │ └── VisualFormatLanguage.swift ├── SupportingFiles ├── Swiftstraints │ └── Info.plist └── SwiftstraintsTests │ └── Info.plist ├── Swiftstraints.podspec ├── Swiftstraints.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ └── xcschemes │ ├── Swiftstraints iOS.xcscheme │ └── Swiftstraints tvOS.xcscheme └── Tests └── SwiftstraintsTests └── SwiftstraintsTests.swift /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | 69 | .DS_Store 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Skyvive 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "Swiftstraints", 8 | platforms: [.iOS(.v9), .tvOS(.v9)], 9 | products: [ 10 | // Products define the executables and libraries a package produces, and make them visible to other packages. 11 | .library( 12 | name: "Swiftstraints", 13 | targets: ["Swiftstraints"]), 14 | ], 15 | dependencies: [ 16 | // Dependencies declare other packages that this package depends on. 17 | // .package(url: /* package url */, from: "1.0.0"), 18 | ], 19 | targets: [ 20 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 21 | // Targets can depend on other targets in this package, and on products in packages this package depends on. 22 | .target( 23 | name: "Swiftstraints", 24 | dependencies: [], 25 | path: "Sources"), 26 | .testTarget( 27 | name: "SwiftstraintsTests", 28 | dependencies: ["Swiftstraints"], 29 | path: "Tests"), 30 | ] 31 | ) 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swiftstraints 2 | 3 | `Swiftstraints` can turn verbose auto-layout code: 4 | ```swift 5 | let constraint = NSLayoutConstraint(item: blueView, 6 | attribute: NSLayoutAttribute.Width, 7 | relatedBy: NSLayoutRelation.Equal, 8 | toItem: redView, 9 | attribute: NSLayoutAttribute.Width, 10 | multiplier: 1.0, 11 | constant: 0.0) 12 | ``` 13 | Into one just one line of code: 14 | ```swift 15 | let constraint = blueView.widthAnchor == redView.widthAnchor 16 | ``` 17 | Or transform your less than consise visual format language code: 18 | ```swift 19 | let constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[leftView]-10-[rightView]|", 20 | options: NSLayoutFormatOptions(0), 21 | metrics: nil, 22 | views: ["leftView":leftView, "rightView":rightView]) 23 | ``` 24 | Into the following: 25 | ``` swift 26 | let constraints = NSLayoutConstraints("H:|[\(leftView)]-10-[\(rightView)]|") 27 | ``` 28 | That was easy! 29 | 30 | ## Installation 31 | 32 | `Swiftstraints` is available through [CocoaPods](http://cocoapods.org). To install, simply include the following lines in your podfile: 33 | ```ruby 34 | use_frameworks! 35 | pod 'Swiftstraints' 36 | ``` 37 | Be sure to import the module at the top of your .swift files: 38 | ```swift 39 | import Swiftstraints 40 | ``` 41 | Alternatively, clone this repo or download it as a zip and include the classes in your project. 42 | 43 | ## Constraints 44 | 45 | With `Swiftstraints` you can create constraints that look just Apple's generic constraint definition: 46 | ```swift 47 | item1.attribute1 = multiplier × item2.attribute2 + constant 48 | ``` 49 | `Swifstraints` utilizes the new layout anchors introduced in iOS 9: 50 | ```swift 51 | let view = UIView() 52 | view.widthAnchor 53 | view.heightAnchor 54 | view.trailingAnchor 55 | view.centerXAnchor 56 | etc... 57 | ``` 58 | `Swiftstraints` implements operator overloading so that you can easily create custom constraints: 59 | ```swift 60 | let blueView = UIView() 61 | let redView = UIView() 62 | let constraint = blueView.heightAnchor == redView.heightAnchor 63 | ``` 64 | Just as you would expect, you can specify a multiplier: 65 | ```swift 66 | let constraint = blueView.heightAnchor == 2.0 * redView.heightAnchor 67 | ``` 68 | Or add a constant: 69 | ```swift 70 | let constraint = blueView.heightAnchor == redView.heightAnchor + 10.0 71 | ``` 72 | You can specify inequalities: 73 | ```swift 74 | let constraint = blueView.heightAnchor <= redView.heightAnchor 75 | ``` 76 | And you can define constant constraints if you so choose: 77 | ```swift 78 | let constraint = blueView.heightAnchor == 100.0 79 | ``` 80 | Swiftstraints can readily compute relatively complex constraints: 81 | ```swift 82 | let constraint = blueView.heightAnchor * 1.4 - 5.0 >= redView.heightAnchor / 3.0 + 400 83 | ``` 84 | It's really easy. 85 | 86 | ## Visual Format Language 87 | 88 | Apple provides an API that lets you create multiple constraints simultaneously with the Visual Format Language. As we saw before it can be a little cumbersome: 89 | ```swift 90 | let constraints = NSLayoutConstraint.constraintsWithVisualFormat("H:|[leftView]-10-[rightView]|", 91 | options: NSLayoutFormatOptions(0), 92 | metrics: nil, 93 | views: ["leftView":leftView, "rightView":rightView]) 94 | ``` 95 | `Swiftstraints` uses string interpolation to let you specify the same constraints in one line of code: 96 | ```swift 97 | let constraints = NSLayoutConstraints("H:|[\(leftView)]-10-[\(rightView)]|") 98 | ``` 99 | `Swiftstraints` also extends `UIView` so that you can add constraints easily using the interpolated string format: 100 | ```swift 101 | superview.addConstraints("H:|[\(leftView)]-10-[\(rightView)]|") 102 | ``` 103 | Super easy, super simple. 104 | ## Revision History 105 | 106 | * 3.0.1 - Bug fixes and limited iOS 8 support (Thank you catjia1011) 107 | * 3.0.0 - Updated to Swift 3 108 | * 2.2.0 - Added support for UILayoutPriority 109 | * 2.1.0 - Fixed a view reference bug and added a new convenience method for adding constraints 110 | * 2.0.2 - Added support for tvOS target. 111 | * 2.0.1 - Updated to include support for axis anchors, increased test coverage and more documentation. 112 | * 2.0.0 - Updated for Swift 2.0 and iOS 9. Now uses layout anchors for simple constraints and string interpolation for Visual Format Language constraints. 113 | * 1.1.0 - Minor API tweaks 114 | * 1.0.0 - Initial Release 115 | 116 | ## Author 117 | 118 | Brad Hilton, brad.hilton.nw@gmail.com 119 | 120 | ## License 121 | 122 | Swiftstraints is available under the MIT license. See the LICENSE file for more info. 123 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/AxisAnchor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AxisAnchor.swift 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 10/22/15. 6 | // Copyright © 2015 Skyvive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | @available(iOS 9.0, *) 13 | public protocol AxisAnchor { 14 | associatedtype AnchorType : AnyObject 15 | var anchor: NSLayoutAnchor { get } 16 | var constant: CGFloat { get } 17 | var priority: LayoutPriority { get } 18 | } 19 | 20 | @available(iOS 9.0, *) 21 | public struct CompoundAxis : AxisAnchor { 22 | public let anchor: NSLayoutAnchor 23 | public let constant: CGFloat 24 | public let priority: LayoutPriority 25 | } 26 | 27 | @available(iOS 9.0, *) 28 | extension AxisAnchor { 29 | 30 | func add(_ addend: CGFloat) -> CompoundAxis { 31 | return CompoundAxis(anchor: anchor, constant: constant + addend, priority: priority) 32 | } 33 | 34 | } 35 | 36 | @available(iOS 9.0, *) 37 | extension NSLayoutXAxisAnchor : AxisAnchor { 38 | public var anchor: NSLayoutAnchor { return self } 39 | public var constant: CGFloat { return 0 } 40 | public var priority: LayoutPriority { return .required } 41 | } 42 | 43 | @available(iOS 9.0, *) 44 | extension NSLayoutYAxisAnchor : AxisAnchor { 45 | public var anchor: NSLayoutAnchor { return self } 46 | public var constant: CGFloat { return 0 } 47 | public var priority: LayoutPriority { return .required } 48 | } 49 | 50 | /// Create a layout constraint from an inequality comparing two axis anchors. 51 | @available(iOS 9.0, *) 52 | public func <=(lhs: T, rhs: U) -> NSLayoutConstraint where T.AnchorType == U.AnchorType { 53 | return lhs.anchor.constraint(lessThanOrEqualTo: rhs.anchor, constant: rhs.constant - lhs.constant).priority(rhs.priority) 54 | } 55 | 56 | /// Create a layout constraint from an equation comparing two axis anchors. 57 | @available(iOS 9.0, *) 58 | public func ==(lhs: T, rhs: U) -> NSLayoutConstraint where T.AnchorType == U.AnchorType { 59 | return lhs.anchor.constraint(equalTo: rhs.anchor, constant: rhs.constant - lhs.constant).priority(rhs.priority) 60 | } 61 | 62 | /// Create a layout constraint from an inequality comparing two axis anchors. 63 | @available(iOS 9.0, *) 64 | public func >=(lhs: T, rhs: U) -> NSLayoutConstraint where T.AnchorType == U.AnchorType { 65 | return lhs.anchor.constraint(greaterThanOrEqualTo: rhs.anchor, constant: rhs.constant - lhs.constant).priority(rhs.priority) 66 | } 67 | 68 | /// Add a constant to an axis anchor. 69 | @available(iOS 9.0, *) 70 | public func +(axis: T, addend: CGFloat) -> CompoundAxis { 71 | return axis.add(addend) 72 | } 73 | 74 | /// Add a constant to an axis anchor. 75 | @available(iOS 9.0, *) 76 | public func +(addend: CGFloat, axis: T) -> CompoundAxis { 77 | return axis.add(addend) 78 | } 79 | 80 | /// Subtract a constant from an axis anchor. 81 | @available(iOS 9.0, *) 82 | public func -(axis: T, subtrahend: CGFloat) -> CompoundAxis { 83 | return axis.add(-subtrahend) 84 | } 85 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/DimensionAnchor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DimensionAnchor.swift 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 10/22/15. 6 | // Copyright © 2015 Skyvive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | @available(iOS 9.0, *) 13 | public protocol DimensionAnchor { 14 | var dimension: NSLayoutDimension { get } 15 | var multiplier: CGFloat { get } 16 | var constant: CGFloat { get } 17 | var priority: LayoutPriority { get } 18 | } 19 | 20 | @available(iOS 9.0, *) 21 | struct CompoundDimension : DimensionAnchor { 22 | let dimension: NSLayoutDimension 23 | let multiplier: CGFloat 24 | let constant: CGFloat 25 | let priority: LayoutPriority 26 | } 27 | 28 | @available(iOS 9.0, *) 29 | extension DimensionAnchor { 30 | 31 | func add(_ addend: CGFloat) -> CompoundDimension { 32 | return CompoundDimension(dimension: dimension, multiplier: multiplier, constant: constant + addend, priority: priority) 33 | } 34 | 35 | func multiply(_ factor: CGFloat) -> CompoundDimension { 36 | return CompoundDimension(dimension: dimension, multiplier: multiplier * factor, constant: constant * factor, priority: priority) 37 | } 38 | 39 | } 40 | 41 | @available(iOS 9.0, *) 42 | extension NSLayoutDimension : DimensionAnchor { 43 | public var dimension: NSLayoutDimension { return self } 44 | public var multiplier: CGFloat { return 1 } 45 | public var constant: CGFloat { return 0 } 46 | public var priority: LayoutPriority { return .required } 47 | } 48 | 49 | /// Create a layout constraint from an inequality comparing a dimension anchor and a constant. 50 | @available(iOS 9.0, *) 51 | public func <=(dimension: DimensionAnchor, constant: CGFloat) -> NSLayoutConstraint { 52 | return dimension.dimension.constraint(lessThanOrEqualToConstant: (constant - dimension.constant)/dimension.multiplier) 53 | } 54 | 55 | /// Create a layout constraint from an equation comparing a dimension anchor and a constant. 56 | @available(iOS 9.0, *) 57 | public func ==(dimension: DimensionAnchor, constant: CGFloat) -> NSLayoutConstraint { 58 | return dimension.dimension.constraint(equalToConstant: (constant - dimension.constant)/dimension.multiplier) 59 | } 60 | 61 | /// Create a layout constraint from an inequality comparing a dimension anchor and a constant. 62 | @available(iOS 9.0, *) 63 | public func >=(dimension: DimensionAnchor, constant: CGFloat) -> NSLayoutConstraint { 64 | return dimension.dimension.constraint(greaterThanOrEqualToConstant: (constant - dimension.constant)/dimension.multiplier) 65 | } 66 | 67 | /// Create a layout constraint from an inequality comparing a dimension anchor and a constant. 68 | @available(iOS 9.0, *) 69 | public func <=(dimension: DimensionAnchor, constant: PrioritizedConstant) -> NSLayoutConstraint { 70 | return dimension.dimension.constraint(lessThanOrEqualToConstant: (constant.constant - dimension.constant)/dimension.multiplier).priority(constant.priority) 71 | } 72 | 73 | /// Create a layout constraint from an equation comparing a dimension anchor and a constant. 74 | @available(iOS 9.0, *) 75 | public func ==(dimension: DimensionAnchor, constant: PrioritizedConstant) -> NSLayoutConstraint { 76 | return dimension.dimension.constraint(equalToConstant: (constant.constant - dimension.constant)/dimension.multiplier).priority(constant.priority) 77 | } 78 | 79 | /// Create a layout constraint from an inequality comparing a dimension anchor and a constant. 80 | @available(iOS 9.0, *) 81 | public func >=(dimension: DimensionAnchor, constant: PrioritizedConstant) -> NSLayoutConstraint { 82 | return dimension.dimension.constraint(greaterThanOrEqualToConstant: (constant.constant - dimension.constant)/dimension.multiplier).priority(constant.priority) 83 | } 84 | 85 | /// Create a layout constraint from an inequality comparing a dimension anchor and a constant. 86 | @available(iOS 9.0, *) 87 | public func <=(constant: CGFloat, dimension: DimensionAnchor) -> NSLayoutConstraint { 88 | return dimension.dimension.constraint(lessThanOrEqualToConstant: (constant - dimension.constant)/dimension.multiplier).priority(dimension.priority) 89 | } 90 | 91 | /// Create a layout constraint from an equation comparing a dimension anchor and a constant. 92 | @available(iOS 9.0, *) 93 | public func ==(constant: CGFloat, dimension: DimensionAnchor) -> NSLayoutConstraint { 94 | return dimension.dimension.constraint(equalToConstant: (constant - dimension.constant)/dimension.multiplier).priority(dimension.priority) 95 | } 96 | 97 | /// Create a layout constraint from an inequality comparing a dimension anchor and a constant. 98 | @available(iOS 9.0, *) 99 | public func >=(constant: CGFloat, dimension: DimensionAnchor) -> NSLayoutConstraint { 100 | return dimension.dimension.constraint(greaterThanOrEqualToConstant: (constant - dimension.constant)/dimension.multiplier).priority(dimension.priority) 101 | } 102 | 103 | /// Create a layout constraint from an inequality comparing two dimension anchors. 104 | @available(iOS 9.0, *) 105 | public func <=(lhs: DimensionAnchor, rhs: DimensionAnchor) -> NSLayoutConstraint { 106 | return lhs.dimension.constraint(lessThanOrEqualTo: rhs.dimension, multiplier: rhs.multiplier/lhs.multiplier, constant: (rhs.constant - lhs.constant)/lhs.multiplier).priority(rhs.priority) 107 | } 108 | 109 | /// Create a layout constraint from an equation comparing two dimension anchors. 110 | @available(iOS 9.0, *) 111 | public func ==(lhs: DimensionAnchor, rhs: DimensionAnchor) -> NSLayoutConstraint { 112 | return lhs.dimension.constraint(equalTo: rhs.dimension, multiplier: rhs.multiplier/lhs.multiplier, constant: (rhs.constant - lhs.constant)/lhs.multiplier).priority(rhs.priority) 113 | } 114 | 115 | /// Create a layout constraint from an inequality comparing two dimension anchors. 116 | @available(iOS 9.0, *) 117 | public func >=(lhs: DimensionAnchor, rhs: DimensionAnchor) -> NSLayoutConstraint { 118 | return lhs.dimension.constraint(greaterThanOrEqualTo: rhs.dimension, multiplier: rhs.multiplier/lhs.multiplier, constant: (rhs.constant - lhs.constant)/lhs.multiplier).priority(rhs.priority) 119 | } 120 | 121 | /// Add a constant to a dimension anchor. 122 | @available(iOS 9.0, *) 123 | public func +(dimension: DimensionAnchor, addend: CGFloat) -> DimensionAnchor { 124 | return dimension.add(addend) 125 | } 126 | 127 | /// Add a constant to a dimension anchor. 128 | @available(iOS 9.0, *) 129 | public func +(addend: CGFloat, dimension: DimensionAnchor) -> DimensionAnchor { 130 | return dimension.add(addend) 131 | } 132 | 133 | /// Subtract a constant from a dimension anchor. 134 | @available(iOS 9.0, *) 135 | public func -(dimension: DimensionAnchor, subtrahend: CGFloat) -> DimensionAnchor { 136 | return dimension.add(-subtrahend) 137 | } 138 | 139 | /// Multiply a dimension anchor by a factor. 140 | @available(iOS 9.0, *) 141 | public func *(dimension: DimensionAnchor, factor: CGFloat) -> DimensionAnchor { 142 | return dimension.multiply(factor) 143 | } 144 | 145 | /// Multiply a dimension anchor by a factor. 146 | @available(iOS 9.0, *) 147 | public func *(factor: CGFloat, dimension: DimensionAnchor) -> DimensionAnchor { 148 | return dimension.multiply(factor) 149 | } 150 | 151 | /// Divide a dimension anchor by a factor. 152 | @available(iOS 9.0, *) 153 | public func /(dimension: DimensionAnchor, divisor: CGFloat) -> DimensionAnchor { 154 | return dimension.multiply(1/divisor) 155 | } 156 | 157 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/LayoutPriority.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutPriority.swift 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 6/15/16. 6 | // Copyright © 2016 Skyvive. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | public enum LayoutPriority { 12 | 13 | case required 14 | case high 15 | case low 16 | case fittingSizeLevel 17 | case other(UILayoutPriority) 18 | 19 | var priority: UILayoutPriority { 20 | switch self { 21 | case .required: return UILayoutPriority.required 22 | case .high: return UILayoutPriority.defaultHigh 23 | case .low: return UILayoutPriority.defaultLow 24 | case .fittingSizeLevel: return UILayoutPriority.fittingSizeLevel 25 | case .other(let priority): return priority 26 | } 27 | } 28 | 29 | } 30 | 31 | public func -(lhs: LayoutPriority, rhs: UILayoutPriority) -> LayoutPriority { 32 | return .other(UILayoutPriority(rawValue: lhs.priority.rawValue - rhs.rawValue)) 33 | } 34 | 35 | public func +(lhs: LayoutPriority, rhs: UILayoutPriority) -> LayoutPriority { 36 | return LayoutPriority.other(UILayoutPriority(rawValue: lhs.priority.rawValue + rhs.rawValue)) 37 | } 38 | 39 | @available(iOS 9.0, *) 40 | public func |(lhs: T, rhs: LayoutPriority) -> CompoundAxis { 41 | return CompoundAxis(anchor: lhs.anchor, constant: lhs.constant, priority: rhs) 42 | } 43 | 44 | @available(iOS 9.0, *) 45 | public func |(dimension: DimensionAnchor, priority: LayoutPriority) -> DimensionAnchor { 46 | return CompoundDimension(dimension: dimension.dimension, multiplier: dimension.multiplier, constant: dimension.constant, priority: priority) 47 | } 48 | 49 | public struct PrioritizedConstant { 50 | let constant: CGFloat 51 | let priority: LayoutPriority 52 | } 53 | 54 | public func |(constant: CGFloat, priority: LayoutPriority) -> PrioritizedConstant { 55 | return PrioritizedConstant(constant: constant, priority: priority) 56 | } 57 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/NSLayoutConstraint+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NSLayoutConstraint+Extensions.swift 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 6/15/16. 6 | // Copyright © 2016 Skyvive. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension NSLayoutConstraint { 12 | 13 | func priority(_ priority: LayoutPriority) -> Self { 14 | self.priority = priority.priority 15 | return self 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/Swiftstraints.h: -------------------------------------------------------------------------------- 1 | // 2 | // Swiftstraints.h 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 5/11/15. 6 | // Copyright (c) 2015 Skyvive. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/UIView+Additions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+Additions.swift 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 10/16/15. 6 | // Copyright © 2015 Skyvive. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension UIView { 12 | 13 | /// Extension to allow addition of multiple constraints in a variadic list. 14 | public func addConstraints(_ constraints: NSLayoutConstraint...) { 15 | addConstraints(constraints) 16 | } 17 | 18 | /// Extension to allow adding of constraints via the visual format language. May also provide NSLayoutFormatOptions as a second parameter. 19 | public func addConstraints(_ constraints: VisualFormatLanguage, options: NSLayoutConstraint.FormatOptions = []) { 20 | addConstraints(constraints.constraints(options)) 21 | } 22 | 23 | /// Extension to allow adding of constraints via the visual format language. May also provide NSLayoutFormatOptions as a second parameter. 24 | public func addConstraints(_ constraints: VisualFormatLanguage..., options: NSLayoutConstraint.FormatOptions = []) { 25 | addConstraints(constraints.reduce([]) { $0 + $1.constraints(options) }) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/VFLComponent.swift: -------------------------------------------------------------------------------- 1 | // 2 | // VFLComponent.swift 3 | // Swiftstraints 4 | // 5 | // Created by Cat Jia on 1/4/2017. 6 | // Copyright © 2017 Skyvive. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | private func vflKey(_ object: AnyObject) -> String { 12 | return "A\(UInt(bitPattern: Unmanaged.passUnretained(object).toOpaque().hashValue))B" 13 | } 14 | 15 | public struct VFLComponent { 16 | public var format = "" 17 | var viewMap = NSMapTable(keyOptions: .copyIn, valueOptions: .weakMemory) 18 | var metricMap = NSMapTable(keyOptions: .copyIn, valueOptions: [.copyIn, .objectPointerPersonality]) 19 | } 20 | 21 | extension VFLComponent: ExpressibleByArrayLiteral { 22 | public typealias Element = UIView 23 | public init(arrayLiteral elements: Element...) { 24 | guard elements.count == 1 else { 25 | fatalError("view component can contains only one UIView instance: \(elements)") 26 | } 27 | let view = elements[0] 28 | let key = vflKey(view) as NSString 29 | viewMap.setObject(view, forKey: key) 30 | self.format = "[\(key)]" 31 | } 32 | } 33 | 34 | extension VFLComponent: ExpressibleByDictionaryLiteral { 35 | public typealias Key = UIView 36 | public typealias Value = VFLComponent 37 | public init(dictionaryLiteral elements: (Key, Value)...) { 38 | guard elements.count == 1 else { 39 | fatalError("view component can contains only one UIView instance: \(elements)") 40 | } 41 | let view = elements[0].0 42 | let numbers = elements[0].1 43 | let key = vflKey(view) as NSString 44 | viewMap.setObject(view, forKey: key) 45 | metricMap = numbers.metricMap 46 | if numbers.isWrapped { 47 | self.format = "[\(key)\(numbers.format)]" 48 | } else { 49 | self.format = "[\(key)(\(numbers.format))]" 50 | } 51 | } 52 | } 53 | 54 | extension VFLComponent: ExpressibleByFloatLiteral, ExpressibleByIntegerLiteral { 55 | public typealias FloatLiteralType = Double 56 | public init(floatLiteral value: FloatLiteralType) { 57 | let number = value as NSNumber 58 | let key = vflKey(number) 59 | metricMap.setObject(number, forKey: key as NSString) 60 | self.format = key 61 | } 62 | public typealias IntegerLiteralType = Int 63 | public init(integerLiteral value: IntegerLiteralType) { 64 | let number = value as NSNumber 65 | let key = vflKey(number) 66 | metricMap.setObject(number, forKey: key as NSString) 67 | self.format = key 68 | } 69 | 70 | } 71 | 72 | extension VFLComponent { 73 | fileprivate var isWrapped: Bool { 74 | return self.format.hasPrefix("(") && self.format.hasSuffix(")") 75 | } 76 | 77 | private func vflDictionary(_ table: NSMapTable) -> [String : AnyObject] { 78 | var dictionary = [String : AnyObject]() 79 | for key in table.keyEnumerator().allObjects { 80 | let key = key as! NSString 81 | dictionary[key as String] = table.object(forKey: key) 82 | } 83 | return dictionary 84 | } 85 | 86 | /// Returns layout constraints with options. 87 | public func constraints(axis: NSLayoutConstraint.Axis, options: NSLayoutConstraint.FormatOptions) -> [NSLayoutConstraint] { 88 | /// fail it if views are changed in case of the weak pointers' targets being deallocated 89 | let keyCount = viewMap.keyEnumerator().allObjects.count 90 | guard let viewCount = viewMap.objectEnumerator()?.allObjects.count, keyCount == viewCount else { return [] } 91 | let axisPrefix: String 92 | switch axis { 93 | case .horizontal: axisPrefix = "H:" 94 | case .vertical: axisPrefix = "V:" 95 | @unknown default: 96 | fatalError("Unexpected axis: \(axis)") 97 | } 98 | return NSLayoutConstraint.constraints(withVisualFormat: axisPrefix + format, options: options, metrics: vflDictionary(metricMap), views: vflDictionary(viewMap)) 99 | } 100 | 101 | } 102 | 103 | 104 | // MARK: - operators 105 | 106 | prefix operator == 107 | prefix operator >= 108 | prefix operator <= 109 | prefix operator | 110 | prefix operator |- 111 | postfix operator | 112 | postfix operator -| 113 | infix operator .~: MultiplicationPrecedence 114 | 115 | /// used for dimensions 116 | public prefix func ==(x: VFLComponent) -> VFLComponent { 117 | var x = x 118 | x.format = "(==" + x.format + ")" 119 | return x 120 | } 121 | public prefix func >=(x: VFLComponent) -> VFLComponent { 122 | var x = x 123 | x.format = "(>=" + x.format + ")" 124 | return x 125 | } 126 | public prefix func <=(x: VFLComponent) -> VFLComponent { 127 | var x = x 128 | x.format = "(<=" + x.format + ")" 129 | return x 130 | } 131 | 132 | public prefix func ==(view: UIView) -> VFLComponent { 133 | var x = [view] as VFLComponent 134 | x.format = "(==" + vflKey(view) + ")" 135 | return x 136 | } 137 | public prefix func >=(view: UIView) -> VFLComponent { 138 | var x = [view] as VFLComponent 139 | x.format = "(>=" + vflKey(view) + ")" 140 | return x 141 | } 142 | public prefix func <=(view: UIView) -> VFLComponent { 143 | var x = [view] as VFLComponent 144 | x.format = "(<=" + vflKey(view) + ")" 145 | return x 146 | } 147 | 148 | 149 | /// used for superview 150 | public prefix func |(x: VFLComponent) -> VFLComponent { 151 | var x = x 152 | x.format = "|" + x.format 153 | return x 154 | } 155 | public prefix func |-(x: VFLComponent) -> VFLComponent { 156 | var x = x 157 | x.format = "|-" + x.format 158 | return x 159 | } 160 | public postfix func |(x: VFLComponent) -> VFLComponent { 161 | var x = x 162 | x.format = x.format + "|" 163 | return x 164 | } 165 | public postfix func -|(x: VFLComponent) -> VFLComponent { 166 | var x = x 167 | x.format = x.format + "-|" 168 | return x 169 | } 170 | 171 | /// used for connections 172 | public func -(lhs: VFLComponent, rhs: VFLComponent) -> VFLComponent { 173 | var result = lhs 174 | result.format = lhs.format + "-" + rhs.format 175 | for key in rhs.viewMap.keyEnumerator().allObjects { 176 | let key = key as! NSString 177 | let view = rhs.viewMap.object(forKey: key) 178 | result.viewMap.setObject(view, forKey: key) 179 | } 180 | for key in rhs.metricMap.keyEnumerator().allObjects { 181 | let key = key as! NSString 182 | let number = rhs.metricMap.object(forKey: key) 183 | result.metricMap.setObject(number, forKey: key) 184 | } 185 | return result 186 | } 187 | 188 | /// used for UILayoutPriority 189 | public func .~(dimension: VFLComponent, priority: LayoutPriority) -> VFLComponent { 190 | var result = dimension 191 | if dimension.isWrapped { 192 | var format = dimension.format 193 | format.remove(at: format.startIndex) 194 | format.remove(at: format.index(format.endIndex, offsetBy: -1)) 195 | result.format = "(\(format)@\(String(describing: priority.priority)))" 196 | } else { 197 | result.format = dimension.format + "@" + String(describing: priority.priority) 198 | } 199 | return result 200 | } 201 | 202 | 203 | /// usages: 204 | /// let constraints = NSLayoutConstraints(H:|-[view1]-(>=5)-[view2]-3-|) 205 | /// NSLayoutConstraints(H:|-30-[versionLabel:==3.~(.high)]-10-[logoView:>=5]-30-|) 206 | /// NSLayoutConstraints(V:|-30-[versionLabel:20]-10-[logoView]-(30.~(.required - 1))-|) 207 | 208 | extension Array where Element == NSLayoutConstraint { 209 | public init(H: VFLComponent, options: NSLayoutConstraint.FormatOptions = []) { 210 | self = H.constraints(axis: .horizontal, options: options) 211 | } 212 | public init(V: VFLComponent, options: NSLayoutConstraint.FormatOptions = []) { 213 | self = V.constraints(axis: .vertical, options: options) 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /Sources/Swiftstraints/VisualFormatLanguage.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LayoutConstraints.swift 3 | // Swiftstraints 4 | // 5 | // Created by Bradley Hilton on 5/12/15. 6 | // Copyright (c) 2015 Skyvive. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | private func vflKey(_ object: AnyObject) -> String { 13 | return "A\(UInt(bitPattern: Unmanaged.passUnretained(object).toOpaque().hashValue))B" 14 | } 15 | 16 | /// Represents constraints created from a interpolated string in the visual format language. 17 | public struct VisualFormatLanguage { 18 | 19 | let format: String 20 | var metrics = NSHashTable(options: [.copyIn, .objectPointerPersonality]) 21 | var views = NSHashTable(options: NSPointerFunctions.Options.weakMemory) 22 | var viewCount: Int = 0 // used to check if this VFL is still valid; since views won't persist the view pointers, if the view is deallocated, there will be an exception when constraints are created later 23 | 24 | public init(stringInterpolation strings: VisualFormatLanguage...) { 25 | var format = "" 26 | for vfl in strings { 27 | format.append(vfl.format) 28 | for metric in vfl.metrics.allObjects { 29 | if !metrics.contains(metric) { 30 | metrics.add(metric) 31 | } 32 | } 33 | for view in vfl.views.allObjects { 34 | if !views.contains(view) { 35 | views.add(view) 36 | viewCount += 1 37 | } 38 | } 39 | } 40 | self.format = format 41 | } 42 | 43 | public init(stringInterpolationSegment expr: T) { 44 | if let view = expr as? UIView { 45 | format = vflKey(view) 46 | views.add(view) 47 | } else if let number = expr as? NSNumber { 48 | format = vflKey(number) 49 | metrics.add(number) 50 | } else { 51 | format = String(describing: expr) 52 | } 53 | } 54 | 55 | func vflDictionary(_ table: NSHashTable) -> [String : AnyObject] { 56 | var dictionary = [String : AnyObject]() 57 | for object in table.allObjects { 58 | dictionary[vflKey(object)] = object 59 | } 60 | return dictionary 61 | } 62 | 63 | /// Returns layout constraints with options. 64 | public func constraints(_ options: NSLayoutConstraint.FormatOptions) -> [NSLayoutConstraint] { 65 | /// fail it if views are changed in case of the weak pointers' targets being deallocated 66 | guard views.count == viewCount else { return [] } 67 | return NSLayoutConstraint.constraints(withVisualFormat: format, options: options, metrics: vflDictionary(metrics), views: vflDictionary(views)) 68 | } 69 | 70 | /// Returns layout constraints. 71 | public var constraints: [NSLayoutConstraint] { 72 | return constraints([]) 73 | } 74 | 75 | } 76 | 77 | extension VisualFormatLanguage : ExpressibleByStringInterpolation { 78 | public typealias StringLiteralType = String 79 | 80 | public struct StringInterpolation : StringInterpolationProtocol { 81 | public typealias StringLiteralType = String 82 | 83 | var format: String = "" 84 | var metrics = NSHashTable(options: [.copyIn, .objectPointerPersonality]) 85 | var views = NSHashTable(options: NSPointerFunctions.Options.weakMemory) 86 | var viewCount: Int = 0 // used to check if this VFL is still valid; since views won't persist the view pointers, if the view is deallocated, there will be an exception when constraints are created later 87 | 88 | public init(literalCapacity: Int, interpolationCount: Int) { 89 | format.reserveCapacity(literalCapacity) 90 | } 91 | 92 | public mutating func appendLiteral(_ literal: String) { 93 | format.append(literal) 94 | } 95 | 96 | public mutating func appendInterpolation(_ metric: NSNumber) { 97 | format.append(vflKey(metric)) 98 | metrics.add(metric) 99 | } 100 | 101 | public mutating func appendInterpolation(_ view: UIView) { 102 | format.append(vflKey(view)) 103 | views.add(view) 104 | viewCount += 1 105 | } 106 | 107 | } 108 | 109 | public init(stringLiteral value: String) { 110 | self.format = value 111 | } 112 | 113 | public init(stringInterpolation: StringInterpolation) { 114 | format = stringInterpolation.format 115 | metrics = stringInterpolation.metrics 116 | views = stringInterpolation.views 117 | viewCount = stringInterpolation.viewCount 118 | } 119 | 120 | } 121 | 122 | public typealias NSLayoutConstraints = [NSLayoutConstraint] 123 | 124 | extension Array where Element : NSLayoutConstraint { 125 | 126 | /// Create a list of constraints using a string interpolated with nested views and metrics. 127 | /// You can optionally include NSLayoutFormatOptions as the second parameter. 128 | public init(_ visualFormatLanguage: VisualFormatLanguage, options: NSLayoutConstraint.FormatOptions = []) { 129 | if let constraints = visualFormatLanguage.constraints(options) as? [Element] { 130 | self = constraints 131 | } else { 132 | self = [] 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /SupportingFiles/Swiftstraints/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SupportingFiles/SwiftstraintsTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Swiftstraints.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Swiftstraints" 3 | s.version = "5.3.0" 4 | s.summary = "Auto Layout Made Easy" 5 | s.description = <<-DESC 6 | Write auto layout constraints in a single line of code. 7 | DESC 8 | s.homepage = "https://github.com/Skyvive/Swiftstraints" 9 | s.license = { :type => "MIT", :file => "LICENSE" } 10 | s.author = { "Brad Hilton" => "brad.hilton.nw@gmail.com" } 11 | s.source = { :git => "https://github.com/Skyvive/Swiftstraints.git", :tag => "5.3.0" } 12 | s.swift_version = '5.0' 13 | s.ios.deployment_target = "8.0" 14 | s.tvos.deployment_target = "9.0" 15 | s.source_files = "Swiftstraints", "Swiftstraints/**/*.{swift,h,m}" 16 | s.requires_arc = true 17 | end 18 | -------------------------------------------------------------------------------- /Swiftstraints.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 4E3DD9FB1E8F941900B33D09 /* VFLComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3DD9FA1E8F941900B33D09 /* VFLComponent.swift */; }; 11 | A20269B11D11DB8100E6088A /* LayoutPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20269B01D11DB8100E6088A /* LayoutPriority.swift */; }; 12 | A20269B31D11DEA900E6088A /* NSLayoutConstraint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20269B21D11DEA900E6088A /* NSLayoutConstraint+Extensions.swift */; }; 13 | A2611A761B01B2980032CB53 /* Swiftstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = A2611A751B01B2980032CB53 /* Swiftstraints.h */; settings = {ATTRIBUTES = (Public, ); }; }; 14 | A2611A7C1B01B2980032CB53 /* Swiftstraints.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A2611A701B01B2980032CB53 /* Swiftstraints.framework */; }; 15 | A2611A831B01B2980032CB53 /* SwiftstraintsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2611A821B01B2980032CB53 /* SwiftstraintsTests.swift */; }; 16 | A266B0871BD967E400821E14 /* AxisAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A266B0861BD967E400821E14 /* AxisAnchor.swift */; }; 17 | A266B0891BD9684800821E14 /* DimensionAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A266B0881BD9684800821E14 /* DimensionAnchor.swift */; }; 18 | A2A827981BD1CC0700E45CAA /* VisualFormatLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A827961BD1CC0700E45CAA /* VisualFormatLanguage.swift */; }; 19 | A2A8279A1BD1CC2900E45CAA /* UIView+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A827991BD1CC2900E45CAA /* UIView+Additions.swift */; }; 20 | A2C4CA0E1B02865C00A4DC56 /* Swiftstraints.podspec in Resources */ = {isa = PBXBuildFile; fileRef = A2C4CA0D1B02865C00A4DC56 /* Swiftstraints.podspec */; }; 21 | F4777CEB1EB0D00C009F2347 /* DimensionAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A266B0881BD9684800821E14 /* DimensionAnchor.swift */; }; 22 | F4777CEC1EB0D00C009F2347 /* VFLComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E3DD9FA1E8F941900B33D09 /* VFLComponent.swift */; }; 23 | F4777CED1EB0D00C009F2347 /* NSLayoutConstraint+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20269B21D11DEA900E6088A /* NSLayoutConstraint+Extensions.swift */; }; 24 | F4777CEE1EB0D00C009F2347 /* UIView+Additions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A827991BD1CC2900E45CAA /* UIView+Additions.swift */; }; 25 | F4777CEF1EB0D00C009F2347 /* VisualFormatLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = A2A827961BD1CC0700E45CAA /* VisualFormatLanguage.swift */; }; 26 | F4777CF01EB0D00C009F2347 /* LayoutPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = A20269B01D11DB8100E6088A /* LayoutPriority.swift */; }; 27 | F4777CF11EB0D00C009F2347 /* AxisAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = A266B0861BD967E400821E14 /* AxisAnchor.swift */; }; 28 | F4777CF41EB0D00C009F2347 /* Swiftstraints.h in Headers */ = {isa = PBXBuildFile; fileRef = A2611A751B01B2980032CB53 /* Swiftstraints.h */; settings = {ATTRIBUTES = (Public, ); }; }; 29 | F4777CF61EB0D00C009F2347 /* Swiftstraints.podspec in Resources */ = {isa = PBXBuildFile; fileRef = A2C4CA0D1B02865C00A4DC56 /* Swiftstraints.podspec */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXContainerItemProxy section */ 33 | A2611A7D1B01B2980032CB53 /* PBXContainerItemProxy */ = { 34 | isa = PBXContainerItemProxy; 35 | containerPortal = A2611A671B01B2980032CB53 /* Project object */; 36 | proxyType = 1; 37 | remoteGlobalIDString = A2611A6F1B01B2980032CB53; 38 | remoteInfo = Swiftstraints; 39 | }; 40 | /* End PBXContainerItemProxy section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 4E3DD9FA1E8F941900B33D09 /* VFLComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VFLComponent.swift; sourceTree = ""; }; 44 | A20269B01D11DB8100E6088A /* LayoutPriority.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutPriority.swift; sourceTree = ""; }; 45 | A20269B21D11DEA900E6088A /* NSLayoutConstraint+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraint+Extensions.swift"; sourceTree = ""; }; 46 | A2611A701B01B2980032CB53 /* Swiftstraints.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swiftstraints.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 47 | A2611A741B01B2980032CB53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | A2611A751B01B2980032CB53 /* Swiftstraints.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Swiftstraints.h; sourceTree = ""; }; 49 | A2611A7B1B01B2980032CB53 /* SwiftstraintsTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SwiftstraintsTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 50 | A2611A811B01B2980032CB53 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 51 | A2611A821B01B2980032CB53 /* SwiftstraintsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftstraintsTests.swift; sourceTree = ""; }; 52 | A266B0861BD967E400821E14 /* AxisAnchor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AxisAnchor.swift; sourceTree = ""; }; 53 | A266B0881BD9684800821E14 /* DimensionAnchor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DimensionAnchor.swift; sourceTree = ""; }; 54 | A2A827961BD1CC0700E45CAA /* VisualFormatLanguage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualFormatLanguage.swift; sourceTree = ""; }; 55 | A2A827991BD1CC2900E45CAA /* UIView+Additions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Additions.swift"; sourceTree = ""; }; 56 | A2C4CA0D1B02865C00A4DC56 /* Swiftstraints.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Swiftstraints.podspec; sourceTree = ""; }; 57 | F4777CFA1EB0D00C009F2347 /* Swiftstraints.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Swiftstraints.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | A2611A6C1B01B2980032CB53 /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | A2611A781B01B2980032CB53 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | A2611A7C1B01B2980032CB53 /* Swiftstraints.framework in Frameworks */, 73 | ); 74 | runOnlyForDeploymentPostprocessing = 0; 75 | }; 76 | F4777CF21EB0D00C009F2347 /* Frameworks */ = { 77 | isa = PBXFrameworksBuildPhase; 78 | buildActionMask = 2147483647; 79 | files = ( 80 | ); 81 | runOnlyForDeploymentPostprocessing = 0; 82 | }; 83 | /* End PBXFrameworksBuildPhase section */ 84 | 85 | /* Begin PBXGroup section */ 86 | A2611A661B01B2980032CB53 = { 87 | isa = PBXGroup; 88 | children = ( 89 | C7B1AF752565779200AF3453 /* SupportingFiles */, 90 | C79AC63025599BBE003DF3A7 /* Sources */, 91 | C79AC63125599BCD003DF3A7 /* Tests */, 92 | A2C4CA0D1B02865C00A4DC56 /* Swiftstraints.podspec */, 93 | A2611A711B01B2980032CB53 /* Products */, 94 | ); 95 | sourceTree = ""; 96 | }; 97 | A2611A711B01B2980032CB53 /* Products */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | A2611A701B01B2980032CB53 /* Swiftstraints.framework */, 101 | A2611A7B1B01B2980032CB53 /* SwiftstraintsTests.xctest */, 102 | F4777CFA1EB0D00C009F2347 /* Swiftstraints.framework */, 103 | ); 104 | name = Products; 105 | sourceTree = ""; 106 | }; 107 | A2611A721B01B2980032CB53 /* Swiftstraints */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | A2611A751B01B2980032CB53 /* Swiftstraints.h */, 111 | A20269B01D11DB8100E6088A /* LayoutPriority.swift */, 112 | A266B0861BD967E400821E14 /* AxisAnchor.swift */, 113 | A266B0881BD9684800821E14 /* DimensionAnchor.swift */, 114 | A20269B21D11DEA900E6088A /* NSLayoutConstraint+Extensions.swift */, 115 | A2A827961BD1CC0700E45CAA /* VisualFormatLanguage.swift */, 116 | 4E3DD9FA1E8F941900B33D09 /* VFLComponent.swift */, 117 | A2A827991BD1CC2900E45CAA /* UIView+Additions.swift */, 118 | ); 119 | path = Swiftstraints; 120 | sourceTree = ""; 121 | }; 122 | A2611A7F1B01B2980032CB53 /* SwiftstraintsTests */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | A2611A821B01B2980032CB53 /* SwiftstraintsTests.swift */, 126 | ); 127 | path = SwiftstraintsTests; 128 | sourceTree = ""; 129 | }; 130 | C79AC63025599BBE003DF3A7 /* Sources */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | A2611A721B01B2980032CB53 /* Swiftstraints */, 134 | ); 135 | path = Sources; 136 | sourceTree = ""; 137 | }; 138 | C79AC63125599BCD003DF3A7 /* Tests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | A2611A7F1B01B2980032CB53 /* SwiftstraintsTests */, 142 | ); 143 | path = Tests; 144 | sourceTree = ""; 145 | }; 146 | C7B1AF752565779200AF3453 /* SupportingFiles */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | C7B1AF77256577CA00AF3453 /* SwiftstraintsTests */, 150 | C7B1AF76256577A500AF3453 /* Swiftstraints */, 151 | ); 152 | path = SupportingFiles; 153 | sourceTree = ""; 154 | }; 155 | C7B1AF76256577A500AF3453 /* Swiftstraints */ = { 156 | isa = PBXGroup; 157 | children = ( 158 | A2611A741B01B2980032CB53 /* Info.plist */, 159 | ); 160 | path = Swiftstraints; 161 | sourceTree = ""; 162 | }; 163 | C7B1AF77256577CA00AF3453 /* SwiftstraintsTests */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | A2611A811B01B2980032CB53 /* Info.plist */, 167 | ); 168 | path = SwiftstraintsTests; 169 | sourceTree = ""; 170 | }; 171 | /* End PBXGroup section */ 172 | 173 | /* Begin PBXHeadersBuildPhase section */ 174 | A2611A6D1B01B2980032CB53 /* Headers */ = { 175 | isa = PBXHeadersBuildPhase; 176 | buildActionMask = 2147483647; 177 | files = ( 178 | A2611A761B01B2980032CB53 /* Swiftstraints.h in Headers */, 179 | ); 180 | runOnlyForDeploymentPostprocessing = 0; 181 | }; 182 | F4777CF31EB0D00C009F2347 /* Headers */ = { 183 | isa = PBXHeadersBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | F4777CF41EB0D00C009F2347 /* Swiftstraints.h in Headers */, 187 | ); 188 | runOnlyForDeploymentPostprocessing = 0; 189 | }; 190 | /* End PBXHeadersBuildPhase section */ 191 | 192 | /* Begin PBXNativeTarget section */ 193 | A2611A6F1B01B2980032CB53 /* Swiftstraints iOS */ = { 194 | isa = PBXNativeTarget; 195 | buildConfigurationList = A2611A861B01B2980032CB53 /* Build configuration list for PBXNativeTarget "Swiftstraints iOS" */; 196 | buildPhases = ( 197 | A2611A6B1B01B2980032CB53 /* Sources */, 198 | A2611A6C1B01B2980032CB53 /* Frameworks */, 199 | A2611A6D1B01B2980032CB53 /* Headers */, 200 | A2611A6E1B01B2980032CB53 /* Resources */, 201 | ); 202 | buildRules = ( 203 | ); 204 | dependencies = ( 205 | ); 206 | name = "Swiftstraints iOS"; 207 | productName = Swiftstraints; 208 | productReference = A2611A701B01B2980032CB53 /* Swiftstraints.framework */; 209 | productType = "com.apple.product-type.framework"; 210 | }; 211 | A2611A7A1B01B2980032CB53 /* SwiftstraintsTests */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = A2611A891B01B2980032CB53 /* Build configuration list for PBXNativeTarget "SwiftstraintsTests" */; 214 | buildPhases = ( 215 | A2611A771B01B2980032CB53 /* Sources */, 216 | A2611A781B01B2980032CB53 /* Frameworks */, 217 | A2611A791B01B2980032CB53 /* Resources */, 218 | ); 219 | buildRules = ( 220 | ); 221 | dependencies = ( 222 | A2611A7E1B01B2980032CB53 /* PBXTargetDependency */, 223 | ); 224 | name = SwiftstraintsTests; 225 | productName = SwiftstraintsTests; 226 | productReference = A2611A7B1B01B2980032CB53 /* SwiftstraintsTests.xctest */; 227 | productType = "com.apple.product-type.bundle.unit-test"; 228 | }; 229 | F4777CE91EB0D00C009F2347 /* Swiftstraints tvOS */ = { 230 | isa = PBXNativeTarget; 231 | buildConfigurationList = F4777CF71EB0D00C009F2347 /* Build configuration list for PBXNativeTarget "Swiftstraints tvOS" */; 232 | buildPhases = ( 233 | F4777CEA1EB0D00C009F2347 /* Sources */, 234 | F4777CF21EB0D00C009F2347 /* Frameworks */, 235 | F4777CF31EB0D00C009F2347 /* Headers */, 236 | F4777CF51EB0D00C009F2347 /* Resources */, 237 | ); 238 | buildRules = ( 239 | ); 240 | dependencies = ( 241 | ); 242 | name = "Swiftstraints tvOS"; 243 | productName = Swiftstraints; 244 | productReference = F4777CFA1EB0D00C009F2347 /* Swiftstraints.framework */; 245 | productType = "com.apple.product-type.framework"; 246 | }; 247 | /* End PBXNativeTarget section */ 248 | 249 | /* Begin PBXProject section */ 250 | A2611A671B01B2980032CB53 /* Project object */ = { 251 | isa = PBXProject; 252 | attributes = { 253 | LastSwiftUpdateCheck = 0700; 254 | LastUpgradeCheck = 1020; 255 | ORGANIZATIONNAME = Skyvive; 256 | TargetAttributes = { 257 | A2611A6F1B01B2980032CB53 = { 258 | CreatedOnToolsVersion = 6.3.1; 259 | LastSwiftMigration = 0920; 260 | }; 261 | A2611A7A1B01B2980032CB53 = { 262 | CreatedOnToolsVersion = 6.3.1; 263 | LastSwiftMigration = 1020; 264 | }; 265 | }; 266 | }; 267 | buildConfigurationList = A2611A6A1B01B2980032CB53 /* Build configuration list for PBXProject "Swiftstraints" */; 268 | compatibilityVersion = "Xcode 3.2"; 269 | developmentRegion = en; 270 | hasScannedForEncodings = 0; 271 | knownRegions = ( 272 | en, 273 | Base, 274 | ); 275 | mainGroup = A2611A661B01B2980032CB53; 276 | productRefGroup = A2611A711B01B2980032CB53 /* Products */; 277 | projectDirPath = ""; 278 | projectRoot = ""; 279 | targets = ( 280 | A2611A6F1B01B2980032CB53 /* Swiftstraints iOS */, 281 | F4777CE91EB0D00C009F2347 /* Swiftstraints tvOS */, 282 | A2611A7A1B01B2980032CB53 /* SwiftstraintsTests */, 283 | ); 284 | }; 285 | /* End PBXProject section */ 286 | 287 | /* Begin PBXResourcesBuildPhase section */ 288 | A2611A6E1B01B2980032CB53 /* Resources */ = { 289 | isa = PBXResourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | A2C4CA0E1B02865C00A4DC56 /* Swiftstraints.podspec in Resources */, 293 | ); 294 | runOnlyForDeploymentPostprocessing = 0; 295 | }; 296 | A2611A791B01B2980032CB53 /* Resources */ = { 297 | isa = PBXResourcesBuildPhase; 298 | buildActionMask = 2147483647; 299 | files = ( 300 | ); 301 | runOnlyForDeploymentPostprocessing = 0; 302 | }; 303 | F4777CF51EB0D00C009F2347 /* Resources */ = { 304 | isa = PBXResourcesBuildPhase; 305 | buildActionMask = 2147483647; 306 | files = ( 307 | F4777CF61EB0D00C009F2347 /* Swiftstraints.podspec in Resources */, 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | /* End PBXResourcesBuildPhase section */ 312 | 313 | /* Begin PBXSourcesBuildPhase section */ 314 | A2611A6B1B01B2980032CB53 /* Sources */ = { 315 | isa = PBXSourcesBuildPhase; 316 | buildActionMask = 2147483647; 317 | files = ( 318 | A266B0891BD9684800821E14 /* DimensionAnchor.swift in Sources */, 319 | 4E3DD9FB1E8F941900B33D09 /* VFLComponent.swift in Sources */, 320 | A20269B31D11DEA900E6088A /* NSLayoutConstraint+Extensions.swift in Sources */, 321 | A2A8279A1BD1CC2900E45CAA /* UIView+Additions.swift in Sources */, 322 | A2A827981BD1CC0700E45CAA /* VisualFormatLanguage.swift in Sources */, 323 | A20269B11D11DB8100E6088A /* LayoutPriority.swift in Sources */, 324 | A266B0871BD967E400821E14 /* AxisAnchor.swift in Sources */, 325 | ); 326 | runOnlyForDeploymentPostprocessing = 0; 327 | }; 328 | A2611A771B01B2980032CB53 /* Sources */ = { 329 | isa = PBXSourcesBuildPhase; 330 | buildActionMask = 2147483647; 331 | files = ( 332 | A2611A831B01B2980032CB53 /* SwiftstraintsTests.swift in Sources */, 333 | ); 334 | runOnlyForDeploymentPostprocessing = 0; 335 | }; 336 | F4777CEA1EB0D00C009F2347 /* Sources */ = { 337 | isa = PBXSourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | F4777CEB1EB0D00C009F2347 /* DimensionAnchor.swift in Sources */, 341 | F4777CEC1EB0D00C009F2347 /* VFLComponent.swift in Sources */, 342 | F4777CED1EB0D00C009F2347 /* NSLayoutConstraint+Extensions.swift in Sources */, 343 | F4777CEE1EB0D00C009F2347 /* UIView+Additions.swift in Sources */, 344 | F4777CEF1EB0D00C009F2347 /* VisualFormatLanguage.swift in Sources */, 345 | F4777CF01EB0D00C009F2347 /* LayoutPriority.swift in Sources */, 346 | F4777CF11EB0D00C009F2347 /* AxisAnchor.swift in Sources */, 347 | ); 348 | runOnlyForDeploymentPostprocessing = 0; 349 | }; 350 | /* End PBXSourcesBuildPhase section */ 351 | 352 | /* Begin PBXTargetDependency section */ 353 | A2611A7E1B01B2980032CB53 /* PBXTargetDependency */ = { 354 | isa = PBXTargetDependency; 355 | target = A2611A6F1B01B2980032CB53 /* Swiftstraints iOS */; 356 | targetProxy = A2611A7D1B01B2980032CB53 /* PBXContainerItemProxy */; 357 | }; 358 | /* End PBXTargetDependency section */ 359 | 360 | /* Begin XCBuildConfiguration section */ 361 | A2611A841B01B2980032CB53 /* Debug */ = { 362 | isa = XCBuildConfiguration; 363 | buildSettings = { 364 | ALWAYS_SEARCH_USER_PATHS = NO; 365 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 366 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 367 | CLANG_CXX_LIBRARY = "libc++"; 368 | CLANG_ENABLE_MODULES = YES; 369 | CLANG_ENABLE_OBJC_ARC = YES; 370 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_COMMA = YES; 373 | CLANG_WARN_CONSTANT_CONVERSION = YES; 374 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 375 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 376 | CLANG_WARN_EMPTY_BODY = YES; 377 | CLANG_WARN_ENUM_CONVERSION = YES; 378 | CLANG_WARN_INFINITE_RECURSION = YES; 379 | CLANG_WARN_INT_CONVERSION = YES; 380 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 381 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 382 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 383 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 384 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 385 | CLANG_WARN_STRICT_PROTOTYPES = YES; 386 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 387 | CLANG_WARN_UNREACHABLE_CODE = YES; 388 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 389 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 390 | COPY_PHASE_STRIP = NO; 391 | CURRENT_PROJECT_VERSION = 1; 392 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 393 | ENABLE_STRICT_OBJC_MSGSEND = YES; 394 | ENABLE_TESTABILITY = YES; 395 | GCC_C_LANGUAGE_STANDARD = gnu99; 396 | GCC_DYNAMIC_NO_PIC = NO; 397 | GCC_NO_COMMON_BLOCKS = YES; 398 | GCC_OPTIMIZATION_LEVEL = 0; 399 | GCC_PREPROCESSOR_DEFINITIONS = ( 400 | "DEBUG=1", 401 | "$(inherited)", 402 | ); 403 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 406 | GCC_WARN_UNDECLARED_SELECTOR = YES; 407 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 408 | GCC_WARN_UNUSED_FUNCTION = YES; 409 | GCC_WARN_UNUSED_VARIABLE = YES; 410 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 411 | MTL_ENABLE_DEBUG_INFO = YES; 412 | ONLY_ACTIVE_ARCH = YES; 413 | SDKROOT = iphoneos; 414 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 415 | SWIFT_VERSION = 4.2; 416 | TARGETED_DEVICE_FAMILY = "1,2"; 417 | VERSIONING_SYSTEM = "apple-generic"; 418 | VERSION_INFO_PREFIX = ""; 419 | }; 420 | name = Debug; 421 | }; 422 | A2611A851B01B2980032CB53 /* Release */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | ALWAYS_SEARCH_USER_PATHS = NO; 426 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 427 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 428 | CLANG_CXX_LIBRARY = "libc++"; 429 | CLANG_ENABLE_MODULES = YES; 430 | CLANG_ENABLE_OBJC_ARC = YES; 431 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 432 | CLANG_WARN_BOOL_CONVERSION = YES; 433 | CLANG_WARN_COMMA = YES; 434 | CLANG_WARN_CONSTANT_CONVERSION = YES; 435 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_EMPTY_BODY = YES; 438 | CLANG_WARN_ENUM_CONVERSION = YES; 439 | CLANG_WARN_INFINITE_RECURSION = YES; 440 | CLANG_WARN_INT_CONVERSION = YES; 441 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 442 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 443 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 444 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 445 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 446 | CLANG_WARN_STRICT_PROTOTYPES = YES; 447 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 448 | CLANG_WARN_UNREACHABLE_CODE = YES; 449 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 450 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 451 | COPY_PHASE_STRIP = NO; 452 | CURRENT_PROJECT_VERSION = 1; 453 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 454 | ENABLE_NS_ASSERTIONS = NO; 455 | ENABLE_STRICT_OBJC_MSGSEND = YES; 456 | GCC_C_LANGUAGE_STANDARD = gnu99; 457 | GCC_NO_COMMON_BLOCKS = YES; 458 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 459 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 460 | GCC_WARN_UNDECLARED_SELECTOR = YES; 461 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 462 | GCC_WARN_UNUSED_FUNCTION = YES; 463 | GCC_WARN_UNUSED_VARIABLE = YES; 464 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 465 | MTL_ENABLE_DEBUG_INFO = NO; 466 | SDKROOT = iphoneos; 467 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 468 | SWIFT_VERSION = 4.2; 469 | TARGETED_DEVICE_FAMILY = "1,2"; 470 | VALIDATE_PRODUCT = YES; 471 | VERSIONING_SYSTEM = "apple-generic"; 472 | VERSION_INFO_PREFIX = ""; 473 | }; 474 | name = Release; 475 | }; 476 | A2611A871B01B2980032CB53 /* Debug */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | CLANG_ENABLE_MODULES = YES; 480 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 481 | DEFINES_MODULE = YES; 482 | DYLIB_COMPATIBILITY_VERSION = 1; 483 | DYLIB_CURRENT_VERSION = 1; 484 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 485 | INFOPLIST_FILE = SupportingFiles/Swiftstraints/Info.plist; 486 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 487 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 488 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 489 | PRODUCT_BUNDLE_IDENTIFIER = "com.skyvive.$(PRODUCT_NAME:rfc1034identifier)"; 490 | PRODUCT_NAME = Swiftstraints; 491 | SKIP_INSTALL = YES; 492 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 493 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 494 | SWIFT_VERSION = 5.0; 495 | }; 496 | name = Debug; 497 | }; 498 | A2611A881B01B2980032CB53 /* Release */ = { 499 | isa = XCBuildConfiguration; 500 | buildSettings = { 501 | CLANG_ENABLE_MODULES = YES; 502 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 503 | DEFINES_MODULE = YES; 504 | DYLIB_COMPATIBILITY_VERSION = 1; 505 | DYLIB_CURRENT_VERSION = 1; 506 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 507 | INFOPLIST_FILE = SupportingFiles/Swiftstraints/Info.plist; 508 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 509 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 510 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 511 | PRODUCT_BUNDLE_IDENTIFIER = "com.skyvive.$(PRODUCT_NAME:rfc1034identifier)"; 512 | PRODUCT_NAME = Swiftstraints; 513 | SKIP_INSTALL = YES; 514 | SWIFT_SWIFT3_OBJC_INFERENCE = Default; 515 | SWIFT_VERSION = 5.0; 516 | }; 517 | name = Release; 518 | }; 519 | A2611A8A1B01B2980032CB53 /* Debug */ = { 520 | isa = XCBuildConfiguration; 521 | buildSettings = { 522 | FRAMEWORK_SEARCH_PATHS = ""; 523 | GCC_PREPROCESSOR_DEFINITIONS = ( 524 | "DEBUG=1", 525 | "$(inherited)", 526 | ); 527 | INFOPLIST_FILE = SupportingFiles/SwiftstraintsTests/Info.plist; 528 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 529 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 530 | PRODUCT_BUNDLE_IDENTIFIER = "com.skyvive.$(PRODUCT_NAME:rfc1034identifier)"; 531 | PRODUCT_NAME = "$(TARGET_NAME)"; 532 | SWIFT_VERSION = 5.0; 533 | }; 534 | name = Debug; 535 | }; 536 | A2611A8B1B01B2980032CB53 /* Release */ = { 537 | isa = XCBuildConfiguration; 538 | buildSettings = { 539 | FRAMEWORK_SEARCH_PATHS = ""; 540 | INFOPLIST_FILE = SupportingFiles/SwiftstraintsTests/Info.plist; 541 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 542 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 543 | PRODUCT_BUNDLE_IDENTIFIER = "com.skyvive.$(PRODUCT_NAME:rfc1034identifier)"; 544 | PRODUCT_NAME = "$(TARGET_NAME)"; 545 | SWIFT_VERSION = 5.0; 546 | }; 547 | name = Release; 548 | }; 549 | F4777CF81EB0D00C009F2347 /* Debug */ = { 550 | isa = XCBuildConfiguration; 551 | buildSettings = { 552 | CLANG_ENABLE_MODULES = YES; 553 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 554 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 555 | DEFINES_MODULE = YES; 556 | DYLIB_COMPATIBILITY_VERSION = 1; 557 | DYLIB_CURRENT_VERSION = 1; 558 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 559 | INFOPLIST_FILE = SupportingFiles/Swiftstraints/Info.plist; 560 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 561 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 562 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 563 | PRODUCT_BUNDLE_IDENTIFIER = "com.skyvive.$(PRODUCT_NAME:rfc1034identifier)"; 564 | PRODUCT_NAME = Swiftstraints; 565 | SDKROOT = appletvos; 566 | SKIP_INSTALL = YES; 567 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 568 | SWIFT_VERSION = 5.0; 569 | TARGETED_DEVICE_FAMILY = 3; 570 | TVOS_DEPLOYMENT_TARGET = 9.0; 571 | }; 572 | name = Debug; 573 | }; 574 | F4777CF91EB0D00C009F2347 /* Release */ = { 575 | isa = XCBuildConfiguration; 576 | buildSettings = { 577 | CLANG_ENABLE_MODULES = YES; 578 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 579 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 580 | DEFINES_MODULE = YES; 581 | DYLIB_COMPATIBILITY_VERSION = 1; 582 | DYLIB_CURRENT_VERSION = 1; 583 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 584 | INFOPLIST_FILE = SupportingFiles/Swiftstraints/Info.plist; 585 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 586 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 587 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 588 | PRODUCT_BUNDLE_IDENTIFIER = "com.skyvive.$(PRODUCT_NAME:rfc1034identifier)"; 589 | PRODUCT_NAME = Swiftstraints; 590 | SDKROOT = appletvos; 591 | SKIP_INSTALL = YES; 592 | SWIFT_VERSION = 5.0; 593 | TARGETED_DEVICE_FAMILY = 3; 594 | TVOS_DEPLOYMENT_TARGET = 9.0; 595 | }; 596 | name = Release; 597 | }; 598 | /* End XCBuildConfiguration section */ 599 | 600 | /* Begin XCConfigurationList section */ 601 | A2611A6A1B01B2980032CB53 /* Build configuration list for PBXProject "Swiftstraints" */ = { 602 | isa = XCConfigurationList; 603 | buildConfigurations = ( 604 | A2611A841B01B2980032CB53 /* Debug */, 605 | A2611A851B01B2980032CB53 /* Release */, 606 | ); 607 | defaultConfigurationIsVisible = 0; 608 | defaultConfigurationName = Release; 609 | }; 610 | A2611A861B01B2980032CB53 /* Build configuration list for PBXNativeTarget "Swiftstraints iOS" */ = { 611 | isa = XCConfigurationList; 612 | buildConfigurations = ( 613 | A2611A871B01B2980032CB53 /* Debug */, 614 | A2611A881B01B2980032CB53 /* Release */, 615 | ); 616 | defaultConfigurationIsVisible = 0; 617 | defaultConfigurationName = Release; 618 | }; 619 | A2611A891B01B2980032CB53 /* Build configuration list for PBXNativeTarget "SwiftstraintsTests" */ = { 620 | isa = XCConfigurationList; 621 | buildConfigurations = ( 622 | A2611A8A1B01B2980032CB53 /* Debug */, 623 | A2611A8B1B01B2980032CB53 /* Release */, 624 | ); 625 | defaultConfigurationIsVisible = 0; 626 | defaultConfigurationName = Release; 627 | }; 628 | F4777CF71EB0D00C009F2347 /* Build configuration list for PBXNativeTarget "Swiftstraints tvOS" */ = { 629 | isa = XCConfigurationList; 630 | buildConfigurations = ( 631 | F4777CF81EB0D00C009F2347 /* Debug */, 632 | F4777CF91EB0D00C009F2347 /* Release */, 633 | ); 634 | defaultConfigurationIsVisible = 0; 635 | defaultConfigurationName = Release; 636 | }; 637 | /* End XCConfigurationList section */ 638 | }; 639 | rootObject = A2611A671B01B2980032CB53 /* Project object */; 640 | } 641 | -------------------------------------------------------------------------------- /Swiftstraints.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Swiftstraints.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Swiftstraints.xcodeproj/xcshareddata/xcschemes/Swiftstraints iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Swiftstraints.xcodeproj/xcshareddata/xcschemes/Swiftstraints tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /Tests/SwiftstraintsTests/SwiftstraintsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftstraintsTests.swift 3 | // SwiftstraintsTests 4 | // 5 | // Created by Bradley Hilton on 5/11/15. 6 | // Copyright (c) 2015 Skyvive. All rights reserved. 7 | // 8 | #if canImport(UIKit) 9 | 10 | import UIKit 11 | import XCTest 12 | @testable import Swiftstraints 13 | 14 | func == (lh: NSLayoutConstraint, rh: NSLayoutConstraint) -> Bool { 15 | return lh.firstItem === rh.firstItem && 16 | lh.firstAttribute == rh.firstAttribute && 17 | lh.relation == rh.relation && 18 | lh.secondItem === rh.secondItem && 19 | lh.secondAttribute == rh.secondAttribute && 20 | lh.multiplier == rh.multiplier && 21 | lh.constant == rh.constant 22 | } 23 | 24 | class SwiftstraintsTests: XCTestCase { 25 | 26 | func testAxisExpressions() { 27 | let view = UIView() 28 | XCTAssert((view.topAnchor + 10).constant == 10) 29 | XCTAssert((10 + view.topAnchor).constant == 10) 30 | XCTAssert((view.topAnchor - 10).constant == -10) 31 | XCTAssert(view.topAnchor.constant == 0) 32 | } 33 | 34 | func testAxisConstraints() { 35 | let view1 = UIView() 36 | let view2 = UIView() 37 | XCTAssert((view1.topAnchor == view2.bottomAnchor) == view1.topAnchor.constraint(equalTo: view2.bottomAnchor)) 38 | XCTAssert((view1.topAnchor == view2.bottomAnchor + 10) == view1.topAnchor.constraint(equalTo: view2.bottomAnchor, constant: 10)) 39 | XCTAssert((view1.topAnchor + 10 == view2.bottomAnchor) == view1.topAnchor.constraint(equalTo: view2.bottomAnchor, constant: -10)) 40 | XCTAssert((view1.topAnchor <= view2.bottomAnchor) == view1.topAnchor.constraint(lessThanOrEqualTo: view2.bottomAnchor)) 41 | XCTAssert((view1.topAnchor >= view2.bottomAnchor) == view1.topAnchor.constraint(greaterThanOrEqualTo: view2.bottomAnchor)) 42 | } 43 | 44 | func testDimensionExpressions() { 45 | let view = UIView() 46 | XCTAssert((view.widthAnchor + 10).constant == 10) 47 | XCTAssert((10 + view.widthAnchor).constant == 10) 48 | XCTAssert((view.widthAnchor * 10).multiplier == 10) 49 | XCTAssert((10 * view.widthAnchor).multiplier == 10) 50 | XCTAssert((view.widthAnchor - 10).constant == -10) 51 | XCTAssert((view.widthAnchor / 10).multiplier == (1/10)) 52 | XCTAssert((view.widthAnchor * 10 + 10).multiplier == 10) 53 | XCTAssert(((view.widthAnchor - 10)*10).constant == -100) 54 | XCTAssert(((view.widthAnchor + 10)/10).constant == 1) 55 | } 56 | 57 | func testDimensionConstraints() { 58 | let view = UIView() 59 | XCTAssert((view.widthAnchor == 10) == view.widthAnchor.constraint(equalToConstant: 10)) 60 | XCTAssert((view.widthAnchor == view.heightAnchor) == view.widthAnchor.constraint(equalTo: view.heightAnchor)) 61 | XCTAssert((view.widthAnchor == view.heightAnchor + 10) == view.widthAnchor.constraint(equalTo: view.heightAnchor, constant: 10)) 62 | XCTAssert((view.widthAnchor == view.heightAnchor*10) == view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 10)) 63 | XCTAssert((view.widthAnchor == view.heightAnchor*10 + 10) == view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 10, constant: 10)) 64 | XCTAssert((view.widthAnchor*2 == view.heightAnchor*4) == view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 2)) 65 | XCTAssert((view.widthAnchor*2 == view.heightAnchor*2 + 2) == view.widthAnchor.constraint(equalTo: view.heightAnchor, constant: 1)) 66 | XCTAssert((view.widthAnchor*3 + 1 <= view.heightAnchor*6 + 7) == view.widthAnchor.constraint(lessThanOrEqualTo: view.heightAnchor, multiplier: 2, constant: 2)) 67 | XCTAssert((view.widthAnchor*3 + 1 == view.heightAnchor*6 + 7) == view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 2, constant: 2)) 68 | XCTAssert((view.widthAnchor*3 + 1 >= view.heightAnchor*6 + 7) == view.widthAnchor.constraint(greaterThanOrEqualTo: view.heightAnchor, multiplier: 2, constant: 2)) 69 | } 70 | 71 | func testPriority() { 72 | let view = UIView() 73 | XCTAssert((view.widthAnchor == view.heightAnchor | .required).priority == UILayoutPriority.required) 74 | XCTAssert((view.widthAnchor == view.heightAnchor | .high).priority == UILayoutPriority.defaultHigh) 75 | XCTAssert((view.widthAnchor == view.heightAnchor | .low).priority == UILayoutPriority.defaultLow) 76 | XCTAssert((view.widthAnchor == view.heightAnchor | .other(UILayoutPriority(rawValue: 0.18))).priority.rawValue == 0.18) 77 | XCTAssert((view.widthAnchor == view.heightAnchor + 10 | .low).priority == UILayoutPriority.defaultLow) 78 | XCTAssert((view.widthAnchor == 10 | .low).priority == UILayoutPriority.defaultLow) 79 | XCTAssert((view.topAnchor == view.bottomAnchor | .high).priority == UILayoutPriority.defaultHigh) 80 | XCTAssert((view.topAnchor == view.bottomAnchor + 10 | .low).priority == UILayoutPriority.defaultLow) 81 | } 82 | 83 | func testVisualFormatLanguage() { 84 | let superview = UIView() 85 | let leftView = UIView() 86 | let rightView = UIView() 87 | superview.addSubview(leftView) 88 | superview.addSubview(rightView) 89 | let shorthandConstraints = NSLayoutConstraints("H:|-8-[\(leftView)(>=80,<=100)]-8-[\(rightView)]-8-|") 90 | let normalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-8-[leftView(>=80,<=100)]-8-[rightView]-8-|", 91 | options: [], 92 | metrics: nil, 93 | views: ["leftView" : leftView, "rightView" : rightView]) 94 | for (lh, rh) in zip(shorthandConstraints, normalConstraints) { 95 | XCTAssert(lh == rh) 96 | } 97 | } 98 | 99 | func testVFLComponent() { 100 | let superview = UIView() 101 | let view1 = UIView() 102 | let view2 = UIView() 103 | superview.addSubview(view1) 104 | superview.addSubview(view2) 105 | 106 | _ = { 107 | let shorthandConstraints = NSLayoutConstraints(H:|-[view1]-(>=5)-[view2]-3-|) 108 | let normalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-[view1]-(>=5)-[view2]-3-|", 109 | options: [], 110 | metrics: nil, 111 | views: ["view1" : view1, "view2" : view2]) 112 | for (lh, rh) in zip(shorthandConstraints, normalConstraints) { 113 | XCTAssert(lh == rh) 114 | } 115 | }() 116 | 117 | _ = { 118 | let shorthandConstraints = NSLayoutConstraints(H:|-[view1]-(>=5)-[view2:==view1]-3-|) 119 | let normalConstraints = NSLayoutConstraint.constraints(withVisualFormat: "H:|-[view1]-(>=5)-[view2(==view1)]-3-|", 120 | options: [], 121 | metrics: nil, 122 | views: ["view1" : view1, "view2" : view2]) 123 | for (lh, rh) in zip(shorthandConstraints, normalConstraints) { 124 | XCTAssert(lh == rh) 125 | } 126 | }() 127 | } 128 | 129 | func testAddConstraints() { 130 | let superview = UIView() 131 | let topView = UIView() 132 | let bottomView = UIView() 133 | superview.addSubview(topView) 134 | superview.addSubview(bottomView) 135 | superview.addConstraints("V:|[\(topView)][\(bottomView)]|") 136 | superview.addConstraints("H:|[\(topView)]|", 137 | "H:|[\(bottomView)]|") 138 | superview.addConstraints(topView.heightAnchor == superview.heightAnchor / 2, 139 | bottomView.heightAnchor == topView.heightAnchor) 140 | } 141 | 142 | } 143 | #endif 144 | --------------------------------------------------------------------------------