# Table of Contents - [Requirements](#requirements) --- # Requirements Requirements ------------ * iOS 8.0+ / Mac OS X 10.11+ / tvOS 9.0+ * Xcode 9.0+ * Swift 4.0+ Communication ------------- * If you **need help**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit) . (Tag ‘snapkit’) * If you’d like to **ask a general question**, use [Stack Overflow](http://stackoverflow.com/questions/tagged/snapkit) . * If you **found a bug**, open an issue. * If you **have a feature request**, open an issue. * If you **want to contribute**, submit a pull request. Installation ------------ ### CocoaPods [CocoaPods](http://cocoapods.org) is a dependency manager for Cocoa projects. You can install it with the following command: $ gem install cocoapods > CocoaPods 1.1.0+ is required to build SnapKit 4.0.0+. To integrate SnapKit into your Xcode project using CocoaPods, specify it in your `Podfile`: source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target '' do pod 'SnapKit', '~> 5.6' end Then, run the following command: $ pod install ### Carthage [Carthage](https://github.com/Carthage/Carthage) is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks. You can install Carthage with [Homebrew](http://brew.sh/) using the following command: $ brew update $ brew install carthage To integrate SnapKit into your Xcode project using Carthage, specify it in your `Cartfile`: github "SnapKit/SnapKit" ~> 5.6 Run `carthage update` to build the framework and drag the built `SnapKit.framework` into your Xcode project. ### Manually If you prefer not to use either of the aforementioned dependency managers, you can integrate SnapKit into your project manually. * * * Usage ----- SnapKit is designed to be extremely easy to use. Let’s say we want to layout a box that is constrained to it’s superview’s edges with 20pts of padding. let box = UIView() superview.addSubview(box) box.snp.makeConstraints { (make) -> Void in make.top.equalTo(superview).offset(20) make.left.equalTo(superview).offset(20) make.bottom.equalTo(superview).offset(-20) make.right.equalTo(superview).offset(-20) } Or even shorter: let box = UIView() superview.addSubview(box) box.snp.makeConstraints { (make) -> Void in make.edges.equalTo(superview).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)) } Not only does this greatly shorten and increase the readability of constraints SnapKit is also taking care of a few crucial steps in the process: * Determining the best common superview to install the constraints on. * Keeping track of the constrainted installed so they can easily be removed later. * Ensuring `translatesAutoresizingMaskIntoConstraints = false` is called on all appropriate views. ### Not all things are created equal > `.equalTo` equivalent to **NSLayoutConstraint.Relation.equal** > `.lessThanOrEqualTo` equivalent to **NSLayoutConstraint.Relation.lessThanOrEqual** > `.greaterThanOrEqualTo` equivalent to **NSLayoutConstraint.Relation.greaterThanOrEqual** These three equality constraints accept one argument which can be any of the following: #### 1\. ViewAttribute make.centerX.lessThanOrEqualTo(view2.snp.left) | ViewAttribute | NSLayoutAttribute | | --- | --- | | view.snp.left | NSLayoutConstraint.Attribute.left | | view.snp.right | NSLayoutConstraint.Attribute.right | | view.snp.top | NSLayoutConstraint.Attribute.top | | view.snp.bottom | NSLayoutConstraint.Attribute.bottom | | view.snp.leading | NSLayoutConstraint.Attribute.leading | | view.snp.trailing | NSLayoutConstraint.Attribute.trailing | | view.snp.width | NSLayoutConstraint.Attribute.width | | view.snp.height | NSLayoutConstraint.Attribute.height | | view.snp.centerX | NSLayoutConstraint.Attribute.centerX | | view.snp.centerY | NSLayoutConstraint.Attribute.centerY | | view.snp.lastBaseline | NSLayoutConstraint.Attribute.lastBaseline | #### 2\. UIView/NSView if you want view.left to be greater than or equal to label.left: // these two constraints are exactly the same make.left.greaterThanOrEqualTo(label) make.left.greaterThanOrEqualTo(label.snp.left) #### 3\. Strict Checks Auto Layout allows width and height to be set to constant values. if you want to set view to have a minimum and maximum width you could pass a primitive to the equality blocks: // width >= 200 && width <= 400 make.width.greaterThanOrEqualTo(200) make.width.lessThanOrEqualTo(400) However Auto Layout does not allow alignment attributes such as left, right, centerY etc to be set to constant values. So if you pass a primitive for these attributes SnapKit will turn these into constraints relative to the view’s superview ie: // creates view.left <= view.superview.left + 10 make.left.lessThanOrEqualTo(10) You can also use other primitives and structs to build your constraints, like so: make.top.equalTo(42) make.height.equalTo(20) make.size.equalTo(CGSize(width: 50, height: 100)) make.edges.equalTo(UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)) make.left.equalTo(view).offset(UIEdgeInsets(top: 10, left: 0, bottom: 10, right: 0)) ### Learn to prioritize > `.priority` allows you to specify an exact priority Priorities can be tacked on to the end of a constraint chain like so: make.top.equalTo(label.snp.top).priority(600) You may also use priority shortcuts: `.low`, `.medium`, `.high`, `.required`. make.top.equalTo(label.snp.top).priority(.medium) ### Composition, composition, composition SnapKit also gives you a few convenience methods to create multiple constraints at the same time. #### edges // make top, left, bottom, right equal view2 make.edges.equalTo(view2); // make top = superview.top + 5, left = superview.left + 10, // bottom = superview.bottom - 15, right = superview.right - 20 make.edges.equalTo(superview).inset(UIEdgeInsets(top: 5, left: 10, bottom: 15, right: 20)) #### size // make width and height greater than or equal to titleLabel make.size.greaterThanOrEqualTo(titleLabel) // make width = superview.width + 100, height = superview.height + 100 make.size.equalTo(superview).offset(100) #### center // make centerX and centerY = button1 make.center.equalTo(button1) // make centerX = superview.centerX + 5, centerY = superview.centerY + 5 make.center.equalTo(superview).offset(5) You can chain view attributes for increased readability: // All edges but the top should equal those of the superview make.left.right.bottom.equalTo(superview) make.top.equalTo(otherView) ### Hold on for dear life Sometimes you need modify existing constraints in order to animate or remove/replace constraints. In SnapKit there are a few different approaches to updating constraints. #### 1\. References You can hold on to a reference of a particular constraint by assigning the result of a constraint make expression to a local variable or a class property. You could also reference multiple constraints by storing them away in an array. var topConstraint: Constraint? = nil ... // when making constraints view1.snp.makeConstraints { (make) -> Void in self.topConstraint = make.top.equalTo(superview).offset(padding.top).constraint make.left.equalTo(superview).offset(padding.left) } ... // then later you can call self.topConstraint.deactivate() // or if you want to update the constraint self.topConstraint.updateOffset(5) ### 2\. snp.updateConstraints Alternative if you are only updating the **constant** value of the constraint you can use the method `snp.updateConstraints` instead of `snp.makeConstraints` // this is Apple's recommended place for adding/updating constraints // this method can get called multiple times in response to setNeedsUpdateConstraints // which can be called by UIKit internally or in your code if you need to trigger an update to your constraints override func updateConstraints() { self.growingButton.snp.updateConstraints { (make) -> Void in make.center.equalTo(self); make.width.equalTo(self.buttonSize.width).priority(250) make.height.equalTo(self.buttonSize.height).priority(250) make.width.lessThanOrEqualTo(self) make.height.lessThanOrEqualTo(self) } // according to Apple super should be called at end of method super.updateConstraints() } ### 3\. snp.remakeConstraints `snp.remakeConstraints` is similar to `snp.makeConstraints`, but will first remove all existing constraints installed by SnapKit. func changeButtonPosition() { self.button.snp.remakeConstraints { (make) -> Void in make.size.equalTo(self.buttonSize) if topLeft { make.top.left.equalTo(10) } else { make.bottom.equalTo(self.view).offset(-10) make.right.equalTo(self.view).offset(-10) } } } ### Snap view to safeAreaLayoutGuide `topLayoutGuide` and `bottomLayoutGuide` were deprecated in `iOS 11`. Use `safeAreaLayoutGuide`: import SnapKit class MyViewController: UIVewController { lazy var tableView = UITableView() override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(tableView) tableView.snp.makeConstraints { (make) -> Void in make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top) } } } ### Debug with ease > `.labeled` allows you to specify constraint labels for debug logs Labels can be tacked on to the end of a constraint chain like so: button.snp.makeConstraints { (make) -> Void in make.top.equalTo(otherView).labeled("buttonViewTopConstraint") } Resulting `Unable to simultaneously satisfy constraints.` logs will use constraint labels to clearly identify which constraints need attention: "" ---