SnapKit은 Autolayout 설정을 간결하고, 편리하게 사용할 수 있게 해주는 프레임워크입니다.
iOS 8.0+, Xcode 9.0+, Swift 4.0+ 에서 사용 가능하고,
CocoaPods, Carthage, Swift Package Manager를 지원합니다.
GitHub - SnapKit/SnapKit: A Swift Autolayout DSL for iOS & OS X
A Swift Autolayout DSL for iOS & OS X. Contribute to SnapKit/SnapKit development by creating an account on GitHub.
github.com
매뉴얼도 잘 제공되어 있습니다.
(SnapKit Docs: https://snapkit.github.io/SnapKit/docs/)
바로 전에 작성한 포스팅에서 썼듯이,
SnapKit은 UIViewControllerRepresentable프로토콜, PreviewProvider프로토콜과 조합하면 사용성이 매우 좋습니다.
아래부터 작성할 예시에서는 위 두 프로토콜을 적용하여 Preview를 함께 보면서 작성하고,
Then 라이브러리로 초기화 작성을 했으니 참고해주세요.
(지난 포스팅: https://swifty-cody.tistory.com/44)
UIViewRepresentable, UIViewControllerRepresentable 프로토콜(feat. PreviewProvider, SnapKit)
SwiftUI가 최근 버전에 와서는 조금 쓸만해졌지만, 쓸만해진 SwiftUI를 쓰려면 Deployment target version이 좀 높아져야 하기도 하고, 타겟 버전을 높였다고 해도 기존 프로젝트에서 많이 사용 중인 UIKit을
swifty-cody.tistory.com
우선 기본 Autolayout의 예시입니다.
보라색 UIView를 ViewController.view의 4방향 anchor에 20씩 제약조건(constraints)를 주어 그리려면 아래와 같이 작성해야 합니다.
class ViewController: UIViewController {
lazy var purpleView = UIView().then {
$0.backgroundColor = .purple
}
override func viewDidLoad() {
super.viewDidLoad()
self.drawSubviews()
}
func drawSubviews() { // subviews의 위치 설정
[purpleView].forEach { // 후에 다른 UIView들 추가 예정
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20).isActive = true
purpleView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -20).isActive = true
purpleView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 20).isActive = true
purpleView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -20).isActive = true
}
}

아래 drawSubviews()는 SnapKit을 이용해서 그린 예시입니다.
SnapKit으로 제약조건을 설정해주고 싶은 UIView에서 .snp.makeConstraints 클로저를 작성해주면 됩니다.
매우 간단한 화면임에도 기존 Autolayout으로는 위처럼 많은 것을 작성해야 했었는데,
SnapKit으로 작성 시 코드가 매우 간결해진 것을 볼 수 있습니다.
func drawSubviews() {
[purpleView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints { make in
make.edges.equalTo(self.view).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}
}
이 경우 모든 edge가 동일하기 때문에
아래처럼 더 줄여주고, 클로저의 '매개변수 in' 부분도 생략해 줄 수 있습니다.
func drawSubviews() {
[purpleView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
}

여기에 기존 Autolayout으로
가로, 세로가 100이고, centerXAnchor가 self.view.centerXAnchor와 같으며 화면 가운데 정렬이 되어 있는
greenView를 추가해주려면 아래와 같이 작성해주는데,
func drawSubviews() {
[purpleView, greenView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
// Autolayout으로 greenView 설정
NSLayoutConstraint.activate([
greenView.widthAnchor.constraint(equalToConstant: 100),
greenView.heightAnchor.constraint(equalToConstant: 100),
greenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
])
}
이는 SnapKit으로 아래처럼 작성할 수 있습니다.
이 또한 이전보다 간결하게 작성할 수 있는 것을 볼 수 있습니다.
func drawSubviews() {
[purpleView, greenView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
// SnapKit으로 greenView 설정
greenView.snp.makeConstraints {
$0.width.height.equalTo(100) // (혹은) $0.size.equalTo(100)
$0.centerX.equalToSuperview()
}
}

이 greenView 아래에 yellowView를 추가해줍니다.
yellowView는 가로, 세로가 greenView의 1.5배 크기에, 50 떨어져 있고, 화면 가운데 정렬이 되어 있는 뷰입니다.
먼저 Autolayout으로 작성하면 아래와 같고,
class ViewController: UIViewController {
lazy var purpleView = UIView().then {
$0.backgroundColor = .purple
}
lazy var greenView = UIView().then {
$0.backgroundColor = .green
}
lazy var yellowView = UIView().then {
$0.backgroundColor = .yellow
}
override func viewDidLoad() {
super.viewDidLoad()
self.drawSubviews()
}
func drawSubviews() {
[purpleView, greenView, yellowView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
greenView.snp.makeConstraints {
$0.width.height.equalTo(100)
$0.centerX.equalToSuperview()
}
// Autolayout으로 yellowView 추가
NSLayoutConstraint.activate([
yellowView.widthAnchor.constraint(equalTo: self.greenView.widthAnchor, multiplier: 1.5),
yellowView.heightAnchor.constraint(equalTo: self.greenView.heightAnchor, multiplier: 1.5),
yellowView.topAnchor.constraint(equalTo: self.greenView.bottomAnchor, constant: 50),
yellowView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
])
}
}
SnapKit으로 작성하면 아래와 같습니다.
.multipliedBy()를 통해 배율을 설정해주고,
다른 뷰의 anchor와의 .constraint(equalTo:constant:) 설정을 .offset()으로 설정해 줄 수 있습니다.
배율이 아니라 나눔으로 하고 싶다면 .dividedBy()를 사용하면 됩니다.
func drawSubviews() {
[purpleView, greenView, yellowView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
greenView.snp.makeConstraints {
$0.width.height.equalTo(100)
$0.centerX.equalToSuperview()
}
// SnapKit으로 yellowView를 작성
yellowView.snp.makeConstraints {
$0.size.equalTo(greenView).multipliedBy(1.5)
$0.top.equalTo(greenView.snp.bottom).offset(50)
$0.centerX.equalToSuperview()
}
}

.equalTo() 외에도
.lessThanOrEqualTo와 .greaterThanOrEqualTo도 있습니다.
.lessThanOrEqualTo는 기본 Autolayout에서 NSLayoutConstraint.Relation.lessThanOrEqual와 동일하고,
.greaterThanOrEqualTo는 NSLayoutConstraint.Relation.greaterThanOrEqual과 동일합니다.
기본적으로 equalTo에 지정해준 치수로 그리지만, 상황에 따라 작아지거나, 커져야하는 경우 사용하게 됩니다.
priority와 shortcut
priority를 정해줄 때는 생성한 제약조건 뒤에 .priority()를 사용해서 설정해줄 수 있고,
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView.snp.width).priority(600)
}
.low, .medium, .high, .required
와 같이 SnapKit에서 제공해주는 shortcut을 사용할 수도 있습니다.
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView.snp.width).priority(.medium)
}
생략할 수 있는 케이스
SnapKit에서 아래와 같이 $0(make)에 추가해 줄 제약조건(width)과
equalTo(혹은 lessThanOrEqualTo, greaterThanOrEqualTo)할 대상(width)이 같을 때,
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView.snp.width)
}
아래처럼 greenView.size에서 .snp.width를 생략해줄 수 있습니다.
이처럼 SnapKit은 .equalTo()의 대상의 제약조건을 생략했을 때, $0의 제약조건과 같은 것으로 정해줍니다.
($0의 width일 때는 greenView의 width로, $0의 size일 때는 greenView의 size로..)
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView)
}
편리한 메서드들 제공
위 예시에서 처럼 SnapKit은 편리한 메서드들을 제공해줍니다.
.edges() 메서드나
purpleView.snp.makeConstraints { make in
$0.edges.equalTo(self.view).inset(20)
// 동일한 코드 (1)
// $0.top.equalTo(self.view).inset(20)
// $0.bottom.equalTo(self.view).inset(20)
// $0.left.equalTo(self.view).inset(20)
// $0.right.equalTo(self.view).inset(20)
// 동일한 코드 (2)
// $0.top.bottom.left.right.equalTo(self.view).inset(20)
// 동일한 코드 (3)
// $0.edges.equalTo(self.view).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}
.size() 메서드,
greenView.snp.makeConstraints {
$0.size.equalTo(100)
// 동일한 코드 (1)
// $0.width.equalTo(100)
// $0.height.equalTo(100)
// 동일한 코드 (2)
// $0.width.height.equalTo(100)
}
.center() 메서드와 같은 편리한 메서드들을 제공해줍니다.
greenView.snp.makeConstraints {
$0.center.equalToSuperview()
// 동일한 코드 (1)
// $0.centerX.equalToSuperview()
// $0.centerY.equalToSuperview()
// 동일한 코드 (2)
// $0.centerX.centerY.equalToSuperview()
}
제약조건(Constraint)의 변경
SnapKit은 생성한 제약조건을 변경할 수 있는 몇가지 접근법을 제공합니다.
1. reference: 변수를 통해 참조하거나, 배열에 넣어서도 참조할 수 있습니다.
var yellowTopConstraint: Constraint? = nil
// constraint 생성
view1.snp.makeConstraints {
self.yellowTopConstraint = $0.top.equalTo(superview).offset(padding.top).constraint
$0.left.equalTo(superview).offset(padding.left)
}
// constraint 비활성화
self.yellowTopConstraint.deactivate()
// constraint 업데이트
self.yellowTopConstraint.updateOffset(5)
2. .snp.updateConstraints: 제약조건의 상수만 변경하는 경우 makeConstrains대신 updateConstraints를 사용합니다.
override func updateConstraints() {
self.purpleView.snp.updateConstraints {
$0.center.equalTo(self);
$0.width.equalTo(self.buttonSize.width).priority(250)
$0.height.equalTo(self.buttonSize.height).priority(250)
$0.width.lessThanOrEqualTo(self)
$0.height.lessThanOrEqualTo(self)
}
// according to Apple super should be called at end of method
super.updateConstraints()
}
3. .snp.remakeConstraints: 기존 설정된 제약조건들을 모두 제거하고 .makeConstraints를 하는 동작입니다.
상황에 따라 화면을 변경하거나 애니메이션을 적용할 때 적합합니다.
func changePurpleViewPosition() {
self.purpleView.snp.remakeConstraints {
$0.size.equalTo(self.purpleViewSize)
if topLeft {
$0.top.left.equalTo(10)
} else {
$0.bottom.equalTo(self.view).offset(-10)
$0.right.equalTo(self.view).offset(-10)
}
}
}
SafeAreaLayoutGuide: iOS11에서 deprecate된 topLayoutGuide, bottomLayoutGuide대신
safeAreaLayoutGuide.snp.top, safeAreaLayoutGuide.snp.bottom 을 사용합니다.
yellowView.snp.makeConstraints {
$0.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
}
.labeled를 통한 debug
Autolayout을 코드로 작성했을 때, 제약조건들이 충돌하게 되면 이를 디버깅하기 쉽지 않은데
.labeled()로 label을 지정해두면 제약조건 충돌시 Debug Log에서 보기 쉽게 알려줍니다.
예를 들어 아래와 같이 yellowView의 size의 multiply와 width를 지정하게 되면,
greenView.snp.makeConstraints {
$0.width.height.equalTo(100).labeled("greenViewSize")
$0.centerX.equalToSuperview().labeled("greenViewCenterX")
}
yellowView.snp.makeConstraints {
$0.size.equalTo(greenView).multipliedBy(1.5).labeled("yellowViewSize")
$0.width.equalTo(85).labeled("yellowViewWidth")
$0.top.equalTo(greenView.snp.bottom).offset(50).labeled("yellowViewTop")
$0.centerX.equalToSuperview().labeled("yellowViewCenterX")
}
런타임시 아래와 같이 Debug Log를 보여줍니다.
어떤 제약조건들이 충돌을 일으키는 것인지 꽤 정확하게 보여줍니다.
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<SnapKit.LayoutConstraint:greenViewSize@ViewController.swift#43 UIView:0x1213067c0.width == 100.0>",
"<SnapKit.LayoutConstraint:yellowViewSize@ViewController.swift#48 UIView:0x121308450.width == UIView:0x1213067c0.width * 1.5>",
"<SnapKit.LayoutConstraint:yellowViewWidth@ViewController.swift#49 UIView:0x121308450.width == 85.0>"
)
Will attempt to recover by breaking constraint
<SnapKit.LayoutConstraint:greenViewSize@ViewController.swift#43 UIView:0x1213067c0.width == 100.0>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.
SnapKit은 Autolayout 설정을 간결하고, 편리하게 사용할 수 있게 해주는 프레임워크입니다.
iOS 8.0+, Xcode 9.0+, Swift 4.0+ 에서 사용 가능하고,
CocoaPods, Carthage, Swift Package Manager를 지원합니다.
GitHub - SnapKit/SnapKit: A Swift Autolayout DSL for iOS & OS X
A Swift Autolayout DSL for iOS & OS X. Contribute to SnapKit/SnapKit development by creating an account on GitHub.
github.com
매뉴얼도 잘 제공되어 있습니다.
(SnapKit Docs: https://snapkit.github.io/SnapKit/docs/)
바로 전에 작성한 포스팅에서 썼듯이,
SnapKit은 UIViewControllerRepresentable프로토콜, PreviewProvider프로토콜과 조합하면 사용성이 매우 좋습니다.
아래부터 작성할 예시에서는 위 두 프로토콜을 적용하여 Preview를 함께 보면서 작성하고,
Then 라이브러리로 초기화 작성을 했으니 참고해주세요.
(지난 포스팅: https://swifty-cody.tistory.com/44)
UIViewRepresentable, UIViewControllerRepresentable 프로토콜(feat. PreviewProvider, SnapKit)
SwiftUI가 최근 버전에 와서는 조금 쓸만해졌지만, 쓸만해진 SwiftUI를 쓰려면 Deployment target version이 좀 높아져야 하기도 하고, 타겟 버전을 높였다고 해도 기존 프로젝트에서 많이 사용 중인 UIKit을
swifty-cody.tistory.com
우선 기본 Autolayout의 예시입니다.
보라색 UIView를 ViewController.view의 4방향 anchor에 20씩 제약조건(constraints)를 주어 그리려면 아래와 같이 작성해야 합니다.
class ViewController: UIViewController {
lazy var purpleView = UIView().then {
$0.backgroundColor = .purple
}
override func viewDidLoad() {
super.viewDidLoad()
self.drawSubviews()
}
func drawSubviews() { // subviews의 위치 설정
[purpleView].forEach { // 후에 다른 UIView들 추가 예정
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 20).isActive = true
purpleView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -20).isActive = true
purpleView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 20).isActive = true
purpleView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: -20).isActive = true
}
}

아래 drawSubviews()는 SnapKit을 이용해서 그린 예시입니다.
SnapKit으로 제약조건을 설정해주고 싶은 UIView에서 .snp.makeConstraints 클로저를 작성해주면 됩니다.
매우 간단한 화면임에도 기존 Autolayout으로는 위처럼 많은 것을 작성해야 했었는데,
SnapKit으로 작성 시 코드가 매우 간결해진 것을 볼 수 있습니다.
func drawSubviews() {
[purpleView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints { make in
make.edges.equalTo(self.view).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}
}
이 경우 모든 edge가 동일하기 때문에
아래처럼 더 줄여주고, 클로저의 '매개변수 in' 부분도 생략해 줄 수 있습니다.
func drawSubviews() {
[purpleView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
}

여기에 기존 Autolayout으로
가로, 세로가 100이고, centerXAnchor가 self.view.centerXAnchor와 같으며 화면 가운데 정렬이 되어 있는
greenView를 추가해주려면 아래와 같이 작성해주는데,
func drawSubviews() {
[purpleView, greenView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
// Autolayout으로 greenView 설정
NSLayoutConstraint.activate([
greenView.widthAnchor.constraint(equalToConstant: 100),
greenView.heightAnchor.constraint(equalToConstant: 100),
greenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
])
}
이는 SnapKit으로 아래처럼 작성할 수 있습니다.
이 또한 이전보다 간결하게 작성할 수 있는 것을 볼 수 있습니다.
func drawSubviews() {
[purpleView, greenView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
// SnapKit으로 greenView 설정
greenView.snp.makeConstraints {
$0.width.height.equalTo(100) // (혹은) $0.size.equalTo(100)
$0.centerX.equalToSuperview()
}
}

이 greenView 아래에 yellowView를 추가해줍니다.
yellowView는 가로, 세로가 greenView의 1.5배 크기에, 50 떨어져 있고, 화면 가운데 정렬이 되어 있는 뷰입니다.
먼저 Autolayout으로 작성하면 아래와 같고,
class ViewController: UIViewController {
lazy var purpleView = UIView().then {
$0.backgroundColor = .purple
}
lazy var greenView = UIView().then {
$0.backgroundColor = .green
}
lazy var yellowView = UIView().then {
$0.backgroundColor = .yellow
}
override func viewDidLoad() {
super.viewDidLoad()
self.drawSubviews()
}
func drawSubviews() {
[purpleView, greenView, yellowView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
greenView.snp.makeConstraints {
$0.width.height.equalTo(100)
$0.centerX.equalToSuperview()
}
// Autolayout으로 yellowView 추가
NSLayoutConstraint.activate([
yellowView.widthAnchor.constraint(equalTo: self.greenView.widthAnchor, multiplier: 1.5),
yellowView.heightAnchor.constraint(equalTo: self.greenView.heightAnchor, multiplier: 1.5),
yellowView.topAnchor.constraint(equalTo: self.greenView.bottomAnchor, constant: 50),
yellowView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor)
])
}
}
SnapKit으로 작성하면 아래와 같습니다.
.multipliedBy()를 통해 배율을 설정해주고,
다른 뷰의 anchor와의 .constraint(equalTo:constant:) 설정을 .offset()으로 설정해 줄 수 있습니다.
배율이 아니라 나눔으로 하고 싶다면 .dividedBy()를 사용하면 됩니다.
func drawSubviews() {
[purpleView, greenView, yellowView].forEach {
self.view.addSubview($0)
$0.translatesAutoresizingMaskIntoConstraints = false
}
purpleView.snp.makeConstraints {
$0.edges.equalToSuperview().inset(20)
}
greenView.snp.makeConstraints {
$0.width.height.equalTo(100)
$0.centerX.equalToSuperview()
}
// SnapKit으로 yellowView를 작성
yellowView.snp.makeConstraints {
$0.size.equalTo(greenView).multipliedBy(1.5)
$0.top.equalTo(greenView.snp.bottom).offset(50)
$0.centerX.equalToSuperview()
}
}

.equalTo() 외에도
.lessThanOrEqualTo와 .greaterThanOrEqualTo도 있습니다.
.lessThanOrEqualTo는 기본 Autolayout에서 NSLayoutConstraint.Relation.lessThanOrEqual와 동일하고,
.greaterThanOrEqualTo는 NSLayoutConstraint.Relation.greaterThanOrEqual과 동일합니다.
기본적으로 equalTo에 지정해준 치수로 그리지만, 상황에 따라 작아지거나, 커져야하는 경우 사용하게 됩니다.
priority와 shortcut
priority를 정해줄 때는 생성한 제약조건 뒤에 .priority()를 사용해서 설정해줄 수 있고,
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView.snp.width).priority(600)
}
.low, .medium, .high, .required
와 같이 SnapKit에서 제공해주는 shortcut을 사용할 수도 있습니다.
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView.snp.width).priority(.medium)
}
생략할 수 있는 케이스
SnapKit에서 아래와 같이 $0(make)에 추가해 줄 제약조건(width)과
equalTo(혹은 lessThanOrEqualTo, greaterThanOrEqualTo)할 대상(width)이 같을 때,
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView.snp.width)
}
아래처럼 greenView.size에서 .snp.width를 생략해줄 수 있습니다.
이처럼 SnapKit은 .equalTo()의 대상의 제약조건을 생략했을 때, $0의 제약조건과 같은 것으로 정해줍니다.
($0의 width일 때는 greenView의 width로, $0의 size일 때는 greenView의 size로..)
yellowView.snp.makeConstraints {
$0.width.equalTo(greenView)
}
편리한 메서드들 제공
위 예시에서 처럼 SnapKit은 편리한 메서드들을 제공해줍니다.
.edges() 메서드나
purpleView.snp.makeConstraints { make in
$0.edges.equalTo(self.view).inset(20)
// 동일한 코드 (1)
// $0.top.equalTo(self.view).inset(20)
// $0.bottom.equalTo(self.view).inset(20)
// $0.left.equalTo(self.view).inset(20)
// $0.right.equalTo(self.view).inset(20)
// 동일한 코드 (2)
// $0.top.bottom.left.right.equalTo(self.view).inset(20)
// 동일한 코드 (3)
// $0.edges.equalTo(self.view).inset(UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20))
}
.size() 메서드,
greenView.snp.makeConstraints {
$0.size.equalTo(100)
// 동일한 코드 (1)
// $0.width.equalTo(100)
// $0.height.equalTo(100)
// 동일한 코드 (2)
// $0.width.height.equalTo(100)
}
.center() 메서드와 같은 편리한 메서드들을 제공해줍니다.
greenView.snp.makeConstraints {
$0.center.equalToSuperview()
// 동일한 코드 (1)
// $0.centerX.equalToSuperview()
// $0.centerY.equalToSuperview()
// 동일한 코드 (2)
// $0.centerX.centerY.equalToSuperview()
}
제약조건(Constraint)의 변경
SnapKit은 생성한 제약조건을 변경할 수 있는 몇가지 접근법을 제공합니다.
1. reference: 변수를 통해 참조하거나, 배열에 넣어서도 참조할 수 있습니다.
var yellowTopConstraint: Constraint? = nil
// constraint 생성
view1.snp.makeConstraints {
self.yellowTopConstraint = $0.top.equalTo(superview).offset(padding.top).constraint
$0.left.equalTo(superview).offset(padding.left)
}
// constraint 비활성화
self.yellowTopConstraint.deactivate()
// constraint 업데이트
self.yellowTopConstraint.updateOffset(5)
2. .snp.updateConstraints: 제약조건의 상수만 변경하는 경우 makeConstrains대신 updateConstraints를 사용합니다.
override func updateConstraints() {
self.purpleView.snp.updateConstraints {
$0.center.equalTo(self);
$0.width.equalTo(self.buttonSize.width).priority(250)
$0.height.equalTo(self.buttonSize.height).priority(250)
$0.width.lessThanOrEqualTo(self)
$0.height.lessThanOrEqualTo(self)
}
// according to Apple super should be called at end of method
super.updateConstraints()
}
3. .snp.remakeConstraints: 기존 설정된 제약조건들을 모두 제거하고 .makeConstraints를 하는 동작입니다.
상황에 따라 화면을 변경하거나 애니메이션을 적용할 때 적합합니다.
func changePurpleViewPosition() {
self.purpleView.snp.remakeConstraints {
$0.size.equalTo(self.purpleViewSize)
if topLeft {
$0.top.left.equalTo(10)
} else {
$0.bottom.equalTo(self.view).offset(-10)
$0.right.equalTo(self.view).offset(-10)
}
}
}
SafeAreaLayoutGuide: iOS11에서 deprecate된 topLayoutGuide, bottomLayoutGuide대신
safeAreaLayoutGuide.snp.top, safeAreaLayoutGuide.snp.bottom 을 사용합니다.
yellowView.snp.makeConstraints {
$0.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
}
.labeled를 통한 debug
Autolayout을 코드로 작성했을 때, 제약조건들이 충돌하게 되면 이를 디버깅하기 쉽지 않은데
.labeled()로 label을 지정해두면 제약조건 충돌시 Debug Log에서 보기 쉽게 알려줍니다.
예를 들어 아래와 같이 yellowView의 size의 multiply와 width를 지정하게 되면,
greenView.snp.makeConstraints {
$0.width.height.equalTo(100).labeled("greenViewSize")
$0.centerX.equalToSuperview().labeled("greenViewCenterX")
}
yellowView.snp.makeConstraints {
$0.size.equalTo(greenView).multipliedBy(1.5).labeled("yellowViewSize")
$0.width.equalTo(85).labeled("yellowViewWidth")
$0.top.equalTo(greenView.snp.bottom).offset(50).labeled("yellowViewTop")
$0.centerX.equalToSuperview().labeled("yellowViewCenterX")
}
런타임시 아래와 같이 Debug Log를 보여줍니다.
어떤 제약조건들이 충돌을 일으키는 것인지 꽤 정확하게 보여줍니다.
[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
Try this:
(1) look at each constraint and try to figure out which you don't expect;
(2) find the code that added the unwanted constraint or constraints and fix it.
(
"<SnapKit.LayoutConstraint:greenViewSize@ViewController.swift#43 UIView:0x1213067c0.width == 100.0>",
"<SnapKit.LayoutConstraint:yellowViewSize@ViewController.swift#48 UIView:0x121308450.width == UIView:0x1213067c0.width * 1.5>",
"<SnapKit.LayoutConstraint:yellowViewWidth@ViewController.swift#49 UIView:0x121308450.width == 85.0>"
)
Will attempt to recover by breaking constraint
<SnapKit.LayoutConstraint:greenViewSize@ViewController.swift#43 UIView:0x1213067c0.width == 100.0>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKitCore/UIView.h> may also be helpful.