지난 1달 반 정도 프로젝트를 진행하면서, 처음으로 SnapKit
을 사용하게 되었다. 사용하면서도 "이게 줄어들면 얼마나 줄어든다고... 왜 쓰지?" 라는 생각을 했었는데, 우연히 옛날 레포를 살펴보다가, NSLayoutConstraint
를 통해서 AutoLayout 설정을 한 코드를 보고 그제서야 깨달았다.
정말 정말 읽기 불편한 이 코드를 무슨 생각으로 썼는지 모르겠다.
오늘은 이러한 생각을 한 김에 한달 반 동안 써본 SnapKit
을 쓰면서 탐구했던 내용들을 블로그에 정리하는 시간을 가져보려고 한다!
자, 무엇이든 개발을 할 때 처음 경험한다면 반드시 읽어야 하는 것이 있다. 바로 공식문서! 왜냐? 만든 놈이 제일 잘 설명하고, 제일 잘 알테니깐!
제일 시작은 일단, 어느 라이브러리와 다를 것 없이 Dependency 추가 방법에 대해서 나오고 있다. 재미 없으니 넘어가겠다.
사용법에서는 일단 사용하기 엄청 쉽다고 자랑하고 있다. 예시로 나와 있는 것이 있는데, UIView
인 box
를 superView로부터 20의 padding 을 주는 코드를 보여주고 있다.
let box = UIView()
superView.addSubView(box)
box.snp.makeConstraints {
$0.edges.equalToSuperView().inset(20)
}
이전에, NSLayoutConstraint
를 통해서 AutoLayout 을 설정하는 것에 비해서 코드가 대폭 줄어든 것을 느낄 수 있을 것이다.
아 그리고 또 한 가지!! 매번 코드 베이스로 UI 를 구현할 때, 정말 정말 귀찮았고 빠지면 에러를 불러일으키는 translatesAutoresizingMaskIntoConstraints = false
... 이것도 대신 해줘서 너무 편리하다.
.equalTo
의 경우는 NSLayoutConstraint.Relation.equal 와 동일.lessThanOrEqualTo
의 경우는 NSLayoutConstraint.Relation.lessThanOrEqual 와 동일.greaterThanOrEqualTo
의 경우는 NSLayoutConstraint.Relation.greaterThanOrEqual 와 동일위와 같이 "동일", "작거나 동일", "크거나 동일" 세 가지의 식을 만들어줄 수 있다.
위에서 소개 해준 등호, 부등호를 사용하기 위해서는 Element
들이 필요할 텐데, 아래와 같다. NSLayoutConstraint
를 사용해봤다면 익히 알던 것들이다.
위에서 소개한 것들을 종합해서 view.left
가 label.left
보다 크거나 같을 경우에는 아래와 같이 코드를 작성하면 된다.
다른 뷰들과의 비교 말고도 상수로도 설정할 수 있는데, 아래와 같이 너비와 높이 값을 상수를 통해서 설정할 수 있다.
// width >= 200 && width <= 400
make.width.greatherThanOrEqualTo(200)
make.width.lessThanOrEqualTo(400)
하지만, Auto Layout 의 경우 left, right, center Y 등등과 같은 alignment 설정에서는 constant Value를 사용하지 못한다는 점! 만약에 주게 된다면?! superView에 대한 설정으로 인식된다고 한다.
// creates view.left <= view.superview.left + 10
make.left.lessThanOrEqualTo(10)
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))
.priority
는 특정 설정에 대한 우선순위를 지정해줄 수 있다.
다들 SnapKit 이 아니더라도 AutoLayout 설정을 할 때 huggingPriority 나 compressionResistencePriority를 설정한 경험이 있을 것이다.
Priority 는 constraint chain 뒤쪽에서 설정해줄 수 있다
make.top.equalTo(label.snp.top).priority(600)
상수를 사용할 수도 있지만, low, medium, high, required 로 열거형으로 지정되어 있는 값들을 사용할 수도 있다.
그리고 위에서 알려준 메서드들로 하나씩 설정할 수도 있지만 한꺼번에 설정해줄 수도 있다.
// make top, left, bottom, right equal view2
make.edges.equalTo(view2)
make.edges.equalTo(superView).inset(UIEdgeInsets(top: 5, left: 10, bottom: 15, right: 15))
// 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)
// make centerX and centerY = button1
make.center.equalTo(button1)
// make centerX = superview.centerX + 5, centerY = superview.centerY + 5
make.center.equalTo(superview).offset(5)
View를 애니메이션화 시키거나 제거하거나 바꾸기 위해서는 기존 Constraint를 수정해야 하는 경우가 있다. SnapKit
에서는 제약 조건을 업데이트 하기 위한 몇 가지 다른 접근 방식이 있다.
Constraint 설정 결과를 로컬 변수 또는 클래스 속성에 할당하여 특정 제약 조건의 참조를 유지할 수 있다. 여러 구속조건을 배열에 저장하여 참조할 수도 있다.
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)
constraint를 변경해줄 때는 snp.makeConstraints
대신해서 snp.updateConstraints
를 사용하면 됩니다.
// 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
// updateConstraints 메서드는 constraints들을 adding 혹은 updating할 때 최적의 장소입니다.
// 이 메서드는 setNeedsUpdateConstraints 혹은 여러 trigger에 의해서 여러 번 호출될 수 있습니다.
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()
}
snp.remakeConstraints
는 snp.makeConstraints
와 비슷합니다. 그러나 remake를 할 경우에는 SnapKit 에 의해서 이제껏 설정해 둔 모든 Constraint가 없어지니 조심해서 사용해야 됩니다.
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)
}
}
}
이상으로, SnapKit 공식문서를 바탕으로 SnapKit 사용 방법에 대해서 알아봤다.
다음 시간에는 마지막으로, SnapKit에서 offset 과 inset의 차이점에 대해서 알아보도록 하자!