iOS 공부를 처음 시작하고 지금까지 항상 view
를 구성할 때 스토리보드에서 Auto Layout
을 잡아 줬었습니다.(항상 짱구😿)
이번에는 스토리보드 없이 코드만으로 View
를 구성하고 Auto Layout
을 설정하는 방법에 대해서 공부 해보겠습니다.
TableView Cell, CollectionView Cell
들을 Custom 하게 만들 때 xib형태로 만들었습니다.
Apple에서 xib 연결을 지원하는건 UIViewController, UITableViewCell, UICollectionViewCell 3가지 입니다.
이와 마찬가지로 xib 형태로 Custom 하게 View를 만들 수 있습니다. 하지만 차이점이 있습니다.
앞선 Custom cell
을 만들때는 xib -> nib 파일로 변환시키는 Unarchiving
과정에서 init(coder: NSCoder) 를 통해 객체를 생성하지 않았지만 Custom View 생성을 위해서는 해당 이니셜라이저를 통해서 객체를 생성해야 합니다.
❗️그럼 왜 custom cell 만들 땐 안하나요? -> awakefFromNib 에서 초기화 해준다고 하는데 좀 더 학습이 필요합니다.
위와 같은 형태의 View 를 반복적으로 사용해야 하는 경우가 있습니다. 우선 view
를 만들고 레이아웃 설정을 해줍니다.
그리고 UIView 를 상속받는 클래스 파일을 하나 만들어서 연결해줍니다.
❗️File's Owner 에서 연결해야 합니다.
❗️Safe Area Layout 가이드 설정해제, Simulator size - Freefrom
import UIKit
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var imageLabel: UILabel!
@IBOutlet weak var contentLabel: UILabel!
required init?(coder: NSCoder) {
super.init(coder: coder)
loadView()
loadUI()
}
func loadView() {
let view = UINib(nibName: "NameCardView", bundle: nil).instantiate(withOwner: self, options: nil).first as! UIView
self.addSubview(view)
view.frame = bounds
view.backgroundColor = .systemCyan
view.clipsToBounds = true
view.layer.cornerRadius = 10
}
func loadUI() {
imageView.image = UIImage(systemName: "star.fill")
imageLabel.textAlignment = .center
imageLabel.text = "TEST"
contentLabel.text = "PLZ"
}
}
그리고 스토리보드에 view 를 하나 추가하고 레이아웃을 설정한 뒤 앞서 작성한 클래스를 상속받도록 하면 결과를 확인할 수 있습니다.
❗️view.frame = bounds 를 적어주지 않으면 스토리보드에서 설정한 레이아웃이 적용되지 않습니다.
❗️ xib -> nib 변환과정을 통해 view를 추가하고 난 뒤에 view에 추가한 객체들을 설정 해야합니다.
이제 위의 과정을 스토리보드를 사용하지 않고, 코드만 이용해서 만들어보겠습니다.
먼저, 커스텀뷰를 코드로 작성해보겠습니다.
class NameCardViewCode: UIView {
let imageView = UIImageView()
let imageLabel = UILabel()
let contentLabel = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
loadLayout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func loadLayout() {
self.addSubview(imageView)
self.addSubview(imageLabel)
self.addSubview(contentLabel)
imageView.translatesAutoresizingMaskIntoConstraints = false
imageLabel.translatesAutoresizingMaskIntoConstraints = false
contentLabel.translatesAutoresizingMaskIntoConstraints = false
imageLabel.textAlignment = .center
imageLabel.font = .boldSystemFont(ofSize: 20)
contentLabel.font = .systemFont(ofSize: 15)
NSLayoutConstraint.activate([
imageView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 18),
imageView.centerYAnchor.constraint(equalTo: centerYAnchor),
imageView.heightAnchor.constraint(equalTo: heightAnchor, multiplier: 0.5),
imageView.widthAnchor.constraint(equalTo: imageView.heightAnchor, multiplier: 0.5)
])
NSLayoutConstraint.activate([
imageLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 18),
imageLabel.topAnchor.constraint(equalTo: imageView.bottomAnchor, constant: 18),
imageLabel.widthAnchor.constraint(equalTo: imageView.widthAnchor)
])
NSLayoutConstraint.activate([
contentLabel.leadingAnchor.constraint(equalTo: imageView.trailingAnchor, constant: 20),
contentLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
contentLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 18)
])
}
}
스토리보드가 아닌 코드로만 구성하기 때문에 xib -> nib
형태로의 변환이 필요하지 않기 때문에 nib 을 load 하는 과정이 필요하지 않고, Coder를 통해서 클래스를 생성할 필요도 없습니다.
🤷♂️그런데 왜 required init?(coder: NSCoder) 을 명시했나요?
UIView, UIViewController 는 NSCoding 프로토콜을 채택하고 있는데 여기서
init?(coder: NSCoder)
을 명시했기 때문에 required 를 붙여서init?(coder: NSCoder)
구현해야만 합니다.
그리고 Auto Layout
을 설정해야 합니다.
세 가지를 이용해서 레이아웃 설정을 할 수 있는데 이번에는 NSLayoutAnchor
를 이용했습니다.
커스텀뷰를 만들었으니, ViewController
에서 코드를 통해 위의 커스텀뷰를 호출하고 화면에 불러오도록 하겠습니다.
class ViewController: UIViewController {
let nameCardView = NameCardViewCode()
override func viewDidLoad() {
super.viewDidLoad()
nameCardView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(nameCardView)
view.backgroundColor = .white
setNameCardView()
}
func setNameCardView() {
nameCardView.backgroundColor = .systemCyan
nameCardView.imageView.image = UIImage(systemName: "star")
nameCardView.imageLabel.text = "TEST"
nameCardView.contentLabel.text = "PLZ"
NSLayoutConstraint.activate([
nameCardView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
nameCardView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 18),
nameCardView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -18),
nameCardView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.3)
])
}
}
커스텀뷰를 만들때와 마찬가지로, 커스텀뷰 클래스를 이용해 인스턴스를 만들고 해당 객체의 레이아웃만 설정해주면 결과를 확인할 수 있습니다.
아직까지는 코드로 레이아웃을 잡는게 익숙하지는 않습니다.. 물론 스토리보드로 설정하는것도 늘 새롭습니다ㅎ
다음에는 Navigation, TabBar
로 구성된 조금은 복잡한 View 를 코드를 이용해서 구성해보고, 레이아웃은 SnapKit
을 이용해서 설정해보도록 하겠습니다.
전체코드는 깃허브를 통해서 확인 할 수 있습니다.