이번에 입사 하게 될 새로운 직장의 앱 레이아웃 구현이
스토리보드와 xib파일들로 구성되어 있다고 전달받았다.
하지만 필자는 Snapkit이라는 오픈소스를 사용하여 코드로 진행하는 걸 추구하고 있었다.
추후에 협업시 예상치 못한 conflict 발생 우려가 첫번째 이유였고
개발을 공부할 당시 맥북이 다소 좋지 않은 사양이어서 로드하는데에 시간이 소요 되었다는 점이 두번째 이유였다.
출근후에 코드로 레이아웃을 구현해도 된다고 전달 받았지만
이미 작성되어있는 부분들의 유지 보수 측면에서도 그렇고
혼자서 코드로 진행을 한다고 해버리면
프로젝트상에서 일관성을 깨버린다고 생각을 했기때문에
빠른 속도로 스토리보드를 이용한 레이아웃 구현을 훑어봤다.
그리고 그 과정에서 코드로 진행 했을때의 느끼지 못했던
앱의 흐름을 시각적으로 볼 수 있다는 점에 큰 인상을 받았다.
또한 레이아웃을 수정하고 빌드하고 했었던 무한 반복 과정을 줄일수 있었다는 점이 나름 편하게 다가왔다.
그리하여 3편에 나눠서
코드, 스토리 보드, 스토리 보드 + xib 으로
tableView의 구현을 포스팅하려 한다.
이번편은 Snapkit을 사용하여 코드로만 진행을 해보겠다.
(Snapkit을 사용하면 Anchor로 진행했을때 보다 비교적 간결하고 쉽게 레이아웃을 작성할 수 있다. & pod install 과정은 생략)
일단 스토리보드가 아닌 코드로 진행한다고 했을때 rootViewContorller 설정 방법을 보겠다.
iOS13 전 까지 하나의 앱에는 하나의 window만 가지고 있었다.
하지만 iOS13부터 window의 개념을 대체하는 scene이라는 것이 나왔고
하나의 앱에서 여러개의 scene을 가질 수 있게 되었다.(ex. 아이패드의 multi window)
그래서 SceneDelegate가 AppDelegate의 역할을 부분적으로 담당하게 되었고 (AppDelegate가 담당하고 있었던 UiLifeCycle - DidEnterBackground, DidBecomeActive 등등..)
rootViewController의 설정 또한 AppDelegate가 아닌 SceneDelegate에서도 설정을 해줄 수 있게 되었다.
AppDelegate
코드 base & Scene을 사용하지 않으며
SceneDelegate 없이 AppDelegate에서 rootVC 설정을 하고자 할때는
plist 파일에서 기본적으로 세팅되어 있는 Appliation Scene Manifest 정보를 삭제하여 Scene Configuration 설정들을 삭제해준다.
스토리보드 설정 또한 삭제해준다.
그리고 SceneDelegate 파일을 삭제하고
SceneDelegate가 생기면서 AppDelegate에 새로 생긴 메소드 2가지(새로운 scene이 생성되거나 삭제될때 호출되는 메소드)를 삭제 해준다.
후에 하단 코드와 같이 rootViewController 설정을 해주면 정상적으로 불러올 수 있으며
SceneDelegate로 이전 되었던 Ui LifeCycle 관련 메소드들은 다시 AppDelegate에서 처리할 수 있게 된다.
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
SceneDelegate
코드 base & 앱이 multi window를 지원할 수 있게 SceneDelegate를 사용하고자 할때는
스토리보드 연결만 끊어준 후에
SceneDelegate에서 window 설정만 해주면 된다.
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
}
TableView
이제 tableView를 추가 해보겠다.
private let tableView = UITableView()
그리고 tableView를 원하는 만큼 레이아웃을 잡아준다.
view.backgroundColor = .red
view.addSubview(tableView)
// 1. superView에 맞게 적용
tableView.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
// 2. safeAreaLayoutGuide에 맞게 적용
tableView.snp.makeConstraints { (make) in
make.edges.equalTo(view.safeAreaLayoutGuide)
}
// 3. superView에 맞게 적용 한 뒤 inset 적용
tableView.snp.makeConstraints { (make) in
make.edges.equalToSuperview().inset(20)
}
Delegate, Datasource
tableView.delegate = self
tableView.datasource = self
Cell
tableView에 cell을 꾸며줄 차례이다.
cell을 custom 하여 진행한다고 가정하겠다.
UITableViewCell을 상속받는 class를 하나 생성하고
cell의 contentView에 imageView와 label을 추가해주었다.
class CharacterCell: UITableViewCell {
let myImageView = UIImageView()
let nameLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
[myImageView, nameLabel].forEach {
contentView.addSubview($0)
}
myImageView.snp.makeConstraints { (make) in
make.top.leading.bottom.equalToSuperview().inset(10)
make.width.height.equalTo(50)
}
nameLabel.snp.makeConstraints { (make) in
make.centerY.equalTo(myImageView)
make.leading.equalTo(myImageView.snp.trailing).offset(10)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
그 다음 cell을 재사용하기 위한 등록 절차를 보겠다.
위에서 생성한 CharacterCell type과 재사용 할 때 식별 할 용도로 사용될 cellID를 넘겨주었다.
tableView.register(CharacterCell.self, forCellReuseIdentifier: "cellID")
그리고 register시 넘겨 주었던 cellID를 사용하여
cell을 불러 오기 위한 작업을 cellForRowAt 메소드 내부에서 처리해주었다.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellID") as? CharacterCell else { return .init() }
.
.
.
return cell
}
이렇게 했을때 하단 좌측 이미지와 같이 cell이 그려지는걸 볼 수 있다.
여기서 잠시 myImageView의 레이아웃 설정 부분을 보겠다.
따로 TableView의 cell 높이를 명시하여 설정 하지 않았을때
bottom 까지 확실하게 마무리 해주어야 cell의 높이가 정상적으로 설정이 된다.
( 상황에 따라 다름. 하단에 또 다른 뷰가 위치하고 있다면 그뷰에 bottom을 살펴보자. 그리고 상단 뷰와의 제약조건 관계도 살펴 봐야한다. )
그렇지 않게 되면 하단 우측 이미지와 같이 흘러내리게 보이는 상황이 발생할 수 있다.
'IOS' 카테고리의 다른 글
[IOS] TableView (with xib) (0) | 2021.02.21 |
---|---|
[IOS] TableView (with Storyboard) (0) | 2021.02.21 |
[IOS] AVPlayer (0) | 2021.01.10 |
[IOS] Timer (0) | 2021.01.07 |
[IOS] UserDefaults (0) | 2021.01.05 |