📌 열번째 프로젝트
스포티파이 구매뷰 앱을 만들어보자
요번 포스팅부터는 ViewController 등 기본 세팅과 AutoLayout의 내용들은 다루지 않겠다! (기억해둘건 당연히 메모해둘것)
1️⃣ AutoLayout
2️⃣ CollectionViewCell 만들기
- BannerCell 이란 이름의 CollectionView cell
//
// BannerCell.swift
// SpotifyPaywall
//
// Created by 오예진 on 2022/06/28.
//
import UIKit
class BannerCell: UICollectionViewCell {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var descriptionLabel: UILabel!
@IBOutlet weak var thumbnailImageView: UIImageView!
// Data 받아서 구성
func configure(_ info: BannerInfo) {
titleLabel.text = info.title
descriptionLabel.text = info.description
thumbnailImageView.image = UIImage(named: info.imageName)
}
}
3️⃣ ViewController 작성
- diffable datasource, snapshot, compositional layout
//
// PaywallViewController.swift
// SpotifyPaywall
//
// Created by 오예진 on 2022/06/28.
//
import UIKit
class PaywallViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var pageControl: UIPageControl!
let bannerInfos: [BannerInfo] = BannerInfo.list
let colors: [UIColor] = [.systemPurple, .systemOrange, .systemPink, .systemRed]
// Section과 Item 꼭 잊지 말기
enum Section {
case main
}
typealias Item = BannerInfo
var datasource: UICollectionViewDiffableDataSource<Section, Item>!
override func viewDidLoad() {
super.viewDidLoad()
// presentation: diffable datasource
datasource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in
// deque = 빼낸다는 의미
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BannerCell", for: indexPath) as? BannerCell else {
return nil
}
cell.configure(item)
cell.backgroundColor = self.colors[indexPath.item] // 배경 색으로 아이템 구별
return cell
})
// data: snapshot
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main]) // snapshot에 section 붙여주기
snapshot.appendItems(bannerInfos, toSection: .main)// snapshot에 item 추가하기
datasource.apply(snapshot)
// layout: compositional layout
collectionView.collectionViewLayout = layout()
}
private func layout() -> UICollectionViewCompositionalLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.8), heightDimension: .absolute(200))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
}
여기까지 하면,,
근데,, 위 코드에서
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
로 했는데 왜 collectionView의 cell들이 수직으로 움직일까?
→ 이유는, 옆으로는 공간 부족이라 받아들여져서 아래로 배치가 된 것이기 때문!
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuous // 수평방향으로!
요롷게 해주면 수평방향으로 움직이게 됨!
이제 촥촥 페이지별로 넘어가게 해보자
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPagingCentered
section.interGroupSpacing = 20 // 아이템들이 서로 떨어지게
groupPagingCentered는 촥촥 넘어갔을때 자동으로 가운데에 맞춰지게 해준다.
groupPaging으로 설정하면, 그냥 촥촥 넘어가게만!
4️⃣ 더 꾸며보기!
- 페이지 둘레를 둥글게
// BannerCell.swift
import UIKit
class BannerCell: UICollectionViewCell {
// ...
override func awakeFromNib() {
super.awakeFromNib()
self.layer.cornerRadius = 16
}
// ...
}
5️⃣ Page Control
- Page Control을 설정하기 위해서는, collectionView 안의 cell들의 index를 정확히 알아야 함
- index를 정확히 알기 위해서는, content size와 offset 등도 알아야 함!
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .groupPagingCentered // 수평방향으로!
section.interGroupSpacing = 20 // 아이템들이 서로 떨어지게
section.visibleItemsInvalidationHandler = { (item, offset, env) in
print(">>> \(env.container.contentSize)")
}
// offset과 contentSize를 계산해서 index 결정하기
let index = Int((offset.x / env.container.contentSize.width).rounded(.up))
print(">>> \(index)")
마무리
//
// PaywallViewController.swift
// SpotifyPaywall
//
// Created by 오예진 on 2022/06/28.
//
import UIKit
class PaywallViewController: UIViewController {
// ...
override func viewDidLoad() {
// ...
// 전체 페이지의 개수?
pageControl.numberOfPages = bannerInfos.count
}
private func layout() -> UICollectionViewCompositionalLayout {
// ...
section.visibleItemsInvalidationHandler = { (item, offset, env) in
// offset과 contentSize를 계산해서 index 결정하기
let index = Int((offset.x / env.container.contentSize.width).rounded(.up))
print(">>> \(index)")
self.pageControl.currentPage = index
}
// ...
}
}
근데 또 오류가 하나 나던데,, 저 collectionView를 위아래로 움직여보면 살짝쿵 움직인다
해결하기 위해!
// layout: compositional layout
collectionView.collectionViewLayout = layout()
// 위아래로 움직이는 거 막기
collectionView.alwaysBounceVertical = false
// 전체 페이지의 개수?
pageControl.numberOfPages = bannerInfos.count
📌 정리,
- Presentation → Diffable DataSource
- Data → Snapshot
- Layout → Compositional Layout
- visibleItemsInvalidationHandler 클로저를 통해 Paging을 위한 index 구하기
section.visibleItemsInvalidationHandler = { (item, offset, env) in
// offset과 contentSize를 계산해서 index 결정하기
let index = Int((offset.x / env.container.contentSize.width).rounded(.up))
self.pageControl.currentPage = index
}
Reference
패스트캠퍼스 온라인 강의
'iOS > Toy project' 카테고리의 다른 글
[iOS : Toy Project] Head Space Focus (2) : Navigation (0) | 2022.06.30 |
---|---|
[iOS : Toy Project] Apple Framework List (3) : Modal (0) | 2022.06.29 |
[iOS : Toy Project] Head Space Focus (0) | 2022.06.07 |
[iOS : Toy Project] Diffable DataSource, Compositional Layout을 이용해 프로젝트 개선하기 (0) | 2022.06.04 |
[iOS : Toy Project] NRC Onboarding (0) | 2022.05.31 |