콜렉션뷰로 작업을 하다보면 복잡한 구현은 힘들겠다는 생각이 들수도 있다.
새로운 방식으로 date,presentation,layout을 바꿔야한다.
import UIKit
class FrameworkListViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
let list: [AppleFramework] = AppleFramework.list
var datasource: UICollectionViewDiffableDataSource<Section,Item>!
typealias Item = AppleFramework
enum Section {
case main
}
// Data, Presentation, Layout
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
navigationController?.navigationBar.topItem?.title = "☀️ Apple Frameworks"
// diffable datasource
// - presentation
datasource = UICollectionViewDiffableDataSource<Section,Item>(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FrameworkCell", for: indexPath) as? FrameworkCell else{
return nil
}
cell.configure(item)
return cell
})
// snapshot
// - data
var snapshot = NSDiffableDataSourceSnapshot<Section,Item>()
snapshot.appendSections([.main])
snapshot.appendItems(list,toSection: .main)
datasource.apply(snapshot)
// compositional layout
// - layout
collectionView.collectionViewLayout = layout()
}
private func layout() -> UICollectionViewCompositionalLayout{
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.33), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(0.33))
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 20)
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
}
extension FrameworkListViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let framework = list[indexPath.item]
print(">>> selected: \(framework.name)")
}
}
뭐가 바뀐지는 알 수 없지만 코드의 형식이 더 복잡해졌고, 복잡하게 개발함으로써 복잡한 구현도 할 수 있다는 것을 알면 되겠다.
이전에 쓰던 방식으로는 모든 셀들이 같은 형태를 유지하지만 이번 예제는 각 셀마다 서로 다른 디자인들이 첨가되어 있다.
또 오토레이아웃관련 문제이다. 요소들과의 관계가 = 이 아니라 >=등으로 설정해줌으로써 파훼했다. 이렇게 되면 스토리보드 자체는 불평하지만 실제로 가동할때는 문제가 없다. 이렇게 코드함으로써, 각 셀마다 설명이 긴 셀이라면 더 길게 보여주는 것을 볼 수 있다.
참고로 라인수를 0으로 지정해주면 무한으로 늘어난다.
uiImage(name)을 UIImage(systemName)으로 변경해주었다.
이미지를 멀티컬러로 저장했음에도 보이지 않는다. 디폴트 값을 변경해주어야한다.
func configure(_ item: Focus){
titleLabel.text = item.title
descriptionLabel.text = item.description
thumnailImageView.image = UIImage(systemName: item.imageName)?.withRenderingMode(.alwaysOriginal)
}
.alwaysTemplate가 디폴트 값이다.
//
// FocusViewController.swift
// HeadSpaceFocus
//
// Created by 이은호 on 2023/02/21.
//
import UIKit
class FocusViewController: UIViewController {
@IBOutlet weak var collectionView: UICollectionView!
var items:[Focus] = Focus.list
typealias Item = Focus
enum Section{
case main
}
@IBOutlet weak var moreBtn: UIButton!
var isAll:Bool = false;
var datasource: UICollectionViewDiffableDataSource<Section,Item>!
override func viewDidLoad() {
super.viewDidLoad()
datasource = UICollectionViewDiffableDataSource<Section,Item>(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "FocusCell", for: indexPath) as? FocusCell else{
return nil
}
cell.configure(item)
return cell
})
// Data: Snapshot
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main])
snapshot.appendItems(items, toSection: .main)
datasource.apply(snapshot)
// Layout
collectionView.collectionViewLayout = layout()
let title = isAll ? "더 많은 날씨 보기":"접기"
moreBtn.setTitle(title, for: .normal)
}
private func layout() -> UICollectionViewCompositionalLayout {
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20)
section.interGroupSpacing = 10
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
@IBAction func btnToggle(_ sender: Any) {
isAll.toggle()
self.items = isAll ? Focus.recommendations : Focus.list
var snapshot = NSDiffableDataSourceSnapshot<Section,Item>()
snapshot.appendSections([.main])
snapshot.appendItems(items,toSection: .main)
datasource.apply(snapshot)
let title = isAll ? "더 많은 날씨 보기":"접기"
moreBtn.setTitle(title, for: .normal)
}
}
버튼과 뷰의 상호작용에 대한 코드를 작성해주면 그만이다. 애니메이션은 자동으로 생성된다 휴~
이번에는 가로스크롤뷰와 세로스크롤뷰가 섞여있는 앱을 만들어보도록 하자.
ㅇ아오 또 날라갔다 중요한점은 온보딩페이징뷰와 다르게 작업한다는 것이다.
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]
enum Section {
case main
}
typealias Item = BannerInfo
var datasource: UICollectionViewDiffableDataSource<Section, Item>!
override func viewDidLoad() {
super.viewDidLoad()
// Presentation
datasource = UICollectionViewDiffableDataSource<Section, Item>.init(collectionView: collectionView, cellProvider: { collectionView, indexPath, item in
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
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections([.main])
snapshot.appendItems(bannerInfos, toSection: .main)
datasource.apply(snapshot)
// layout
collectionView.collectionViewLayout = layout()
collectionView.alwaysBounceVertical = false
self.pageControl.numberOfPages = bannerInfos.count
}
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)
section.orthogonalScrollingBehavior = .groupPagingCentered
section.interGroupSpacing = 20
section.visibleItemsInvalidationHandler = { (items, offset, env) in
let index = Int((offset.x / env.container.contentSize.width).rounded(.up))
print("--> \(index)")
self.pageControl.currentPage = index
}
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
}
[https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views] 여기에 수많은 예제들이 있음으로 참고해서 작성해주면된다.
코드를 선택한후 커맨드+? 를 입력한다.
기본적으로 선형탐색과 해시테이블의 성능차이가 어마어마한것은 알것이다. 그리고 스위프트는 자료구조를 반 드 시 해시형으로 선언해야 하는 경우가 있다.
참고