🤔왜 이걸 쓰지?
개발 시 스토리보드를 사용하여 화면의 UI를 구성할 수도 있지만 Autolayout을 코드로 작성하는 방법도 있다.
NSLayoutConstraint를 직접 지정해주며 하나하나 제약을 적용해 주는 방법이 그것인데, 화면을 구성하는 UI요소들이 많아질 수록 제약에 필요한 코드양이 상당해지며 가독성도 그리 좋지 못하다고 느꼈다.
SnapKit은 간결한 코드로 NSLayoutConstraint를 쉽게 제어할 수 있도록 해준다.
간단히 SnapKit사용법과 샘플프로젝트에 적용해본다.
그럼 시작해보자.
프로젝트에 SnapKit을 import해보자.
난 SPM(SwiftPackageManager )를 사용해서 추가해줬다. SPM 편해.
ViewController.swift를 열자.
SnapKit을 import해주고 UIView 변수를 만들어준다.
addSubView를 통해 만든 뷰(이하 box)를 붙인다.
이제 부터 box에 제약을 걸어줄건데, 이전과 같았으면
box.translatesAutoresizingMaskIntoConstraints = false
를 선행코드로 해줬을 것이다.
하지만 SnapKit은 위 코드를 내부에서 해주기 때문에 쓸 필요가 없다.
translatesAutoresizingMaskIntoConstraints 이란,
UIView의 인스턴스 프로퍼티이며, autoResizingMask가 autoLayoutConstraint로 변환되는지 여부를 결정한다. 코드로 직접 제약을 줄 때 우린 이 값을 false로 설정하고 시작해야한다.
UIView에서 snp프로토콜을 사용할 수있다.
box.snp.makeConstraints { make in
make.width.height.equalTo(100)
}
width와 height의 값을 100으로 정해줬다.
단 한줄로 크기제약을 적용해줬다. 매우 간결하고 직관적이다.
여기에 위치제약까지 적용해보자. 화면의 중심에 box를 위치시켜본다.
box.snp.makeConstraints { make in
make.width.height.equalTo(100)
make.center.equalToSuperview()
}
크기제약 밑에 위치제약까지 추가해줬다.
이상태로 시뮬레이터로 Box가 정상적으로 노출되는지 확인해보자.
의도한 대로 잘 보여진다.
이것을 SnapKit을 사용하지 않고 코드로 작성했다면 아래와 같다.
극단적으로 길게 만든 코드이긴 하지만, 이렇게 장황하게 쓸수도 있다…
box.translatesAutoresizingMaskIntoConstraints = false
let constraintHeight = NSLayoutConstraint(item: box,
attribute: .height,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1.0,
constant: 100)
let constraintWidth = NSLayoutConstraint.init(item: box,
attribute: .width,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1.0,
constant: 100)
let constraintCenterX = NSLayoutConstraint.init(item: box,
attribute: .centerX,
relatedBy: .equal,
toItem: self.view,
attribute: .centerX,
multiplier: 1.0,
constant: 0)
let constraintCenterY = NSLayoutConstraint.init(item: box,
attribute: .centerY,
relatedBy: .equal,
toItem: self.view,
attribute: .centerY,
multiplier: 1.0,
constant: 0)
box.addConstraints([constraintHeight, constraintWidth])
self.view.addConstraints([ constraintCenterX, constraintCenterY])
SnapKit을 통해 UI에 크기와 위치 제약조건을 걸어줘봤다.
다른 제약들도 적용해보자. 상하 좌우제약은 아래와같다.
let orangeBox = UIView()
orangeBox.backgroundColor = .orange
self.view.addSubview(orangeBox)
orangeBox.snp.makeConstraints { make in
make.bottom.left.right.top.equalToSuperview()
}
view의 상하좌우와 orangeBox의 상하좌우를 같게 만들었다.
여기서 좌 우 의 간격을 10만큼 띄워줘보자.
적용하고 싶은 제약조건 뒤에 offset을 추가해주면 된다.
orangeBox.snp.makeConstraints { make in
make.bottom.top.equalToSuperview()
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
}
최종적으로 이리저리 적용해본 코드는 아래와 같다.
요즘 SnapKit으로 작업하는 회사도 많다던데 다음 개인프로젝트는 SnapKit으로 작업해보는건 어떨까 싶다.
import UIKit
import SnapKit
class ViewController: UIViewController {
let redBox = UIView()
let orangeBox = UIView()
let blueBox = UIView()
let greenBox = UIView()
let uiUpdateButton = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(redBox)
self.view.addSubview(orangeBox)
self.view.addSubview(blueBox)
self.view.addSubview(greenBox)
self.view.addSubview(uiUpdateButton)
redBox.backgroundColor = .red
orangeBox.backgroundColor = .orange
blueBox.backgroundColor = .blue
greenBox.backgroundColor = .green
redBox.snp.remakeConstraints { make in
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.height.equalTo(50)
make.top.equalTo(self.view.safeAreaLayoutGuide)
}
orangeBox.snp.makeConstraints { make in
make.top.equalTo(redBox.snp.bottom).offset(10)
make.left.right.equalTo(redBox)
make.height.equalTo(50)
}
blueBox.snp.makeConstraints { make in
make.left.equalTo(orangeBox)
make.height.equalTo(50)
make.top.equalTo(orangeBox.snp.bottom).offset(10)
make.right.equalTo(greenBox.snp.left).offset(-10)
make.width.equalTo(greenBox)
}
greenBox.snp.makeConstraints { make in
make.right.equalTo(orangeBox)
make.height.equalTo(50)
make.top.equalTo(orangeBox.snp.bottom).offset(10)
make.left.equalTo(blueBox.snp.right).offset(10)
make.width.equalTo(blueBox)
}
uiUpdateButton.backgroundColor = .gray
uiUpdateButton.setTitle("Update", for: .normal)
uiUpdateButton.snp.makeConstraints { make in
make.left.equalToSuperview().offset(10)
make.right.equalToSuperview().offset(-10)
make.height.equalTo(50)
make.bottom.equalTo(self.view.safeAreaLayoutGuide).offset(-10)
}
uiUpdateButton.addTarget(self, action: #selector(updateUILayout), for: .touchUpInside)
}
@objc func updateUILayout() {
redBox.snp.updateConstraints { make in
make.height.equalTo(100)
}
orangeBox.snp.updateConstraints { make in
make.height.equalTo(100)
}
blueBox.snp.updateConstraints { make in
make.height.equalTo(100)
}
greenBox.snp.updateConstraints { make in
make.height.equalTo(100)
}
uiUpdateButton.snp.updateConstraints { make in
make.height.equalTo(100)
}
}
}