모델 정의
collectionview cell에 들어갈 데이터의 모델을 정의한다.
struct Model {
var color: Int
}
SectionModel 정의
section을 구분할 열거형을 만들고 SectionModelType
프로토콜을 채택한다. Item
의 타입과 items
를 구현해야 한다.Item typealias
를 정의한다. Item typealias는 section안에 들어갈 item의 타입과 동일하다.
public protocol SectionModelType {
associatedtype Item
var items: [Item] { get }
init(original: Self, items: [Item])
}
다중 섹션을 구현할 것이기 때문에 열거형으로 각 section에 들어갈 item과 SectionModel를 정의한다.
import RxDataSources
enum SectionItem {
case firstItem(model: Model)
case secondItem(model: Model)
}
enum CollectionViewSectionModel {
case firstSection(items: [SectionItem])
case secondSection(items: [SectionItem])
}
extension CollectionViewSectionModel: SectionModelType {
typealias Item = SectionItem
var items: [SectionItem] {
switch self {
case .firstSection(let items):
return items
case .secondSection(let items):
return items
}
}
init(original: Self, items: [Self.Item]) {
self = original
}
}
datasource 만들기
위에서 만든 sectionModel
타입의 dataSource 객체를 만든다.
typealias DataSource = RxCollectionViewSectionedReloadDataSource
let dataSource = DataSource<CollectionViewSectionModel> { dataSource, collectionView, indexPath, item in
switch dataSource[indexPath] {
case .firstItem(let model):
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OneCollectionViewCell.identifier,
for: indexPath) as? OneCollectionViewCell else {
return UICollectionViewCell()
}
cell.backgroundColor = UIColor(hex: model.color)
return cell
case .secondItem(let model):
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TwoCollectionViewCell.identifier,
for: indexPath) as? TwoCollectionViewCell else {
return UICollectionViewCell()
}
cell.backgroundColor = UIColor(hex: model.color)
return cell
}
}
collection view에 전달할 데이터 만들기
let hex = [0x779c74, 0xcaa94d, 0x32c96e, 0xd499d4, 0xe2cce7,
0xa8daf9, 0xe85255, 0xe3272b, 0x7f0909, 0xdedede]
var firstItems = [SectionItem]()
var secondItems = [SectionItem]()
hex.forEach{ firstItems.append(.firstItem(model: Model(color: $0))) }
hex.forEach{ secondItems.append(.secondItem(model: Model(color: $0))) }
let colorObservable = BehaviorSubject<[CollectionViewSectionModel]>(value: [
.firstSection(items: firstItems),
.secondSection(items: secondItems)
])
var items: Driver<[CollectionViewSectionModel]>
var dataSource: DataSource<CollectionViewSectionModel>
self.items = colorObservable.asDriver(onErrorJustReturn: [])
self.dataSource = dataSource
binding
viewModel.outputs.items
.drive(collectionView.rx.items(dataSource: viewModel.outputs.dataSource))
.disposed(by: rx.disposeBag)
compositional layout code
func layout() -> UICollectionViewCompositionalLayout {
let layout = UICollectionViewCompositionalLayout { section, _ in
switch section {
case 0:
let item = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)))
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
let verticalGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(360)),
subitem: item,
count: 3)
let horizontalGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.95),
heightDimension: .absolute(360)),
subitem: verticalGroup,
count: 1)
let section = NSCollectionLayoutSection(group: horizontalGroup)
section.orthogonalScrollingBehavior = .groupPaging
return section
case 1:
let item = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .absolute(200),
heightDimension: .absolute(200)))
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
let verticalGroup = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(widthDimension: .absolute(200),
heightDimension: .absolute(400)),
subitem: item,
count: 2)
let horizontalGroup = NSCollectionLayoutGroup.horizontal(
layoutSize: NSCollectionLayoutSize(widthDimension: .absolute(200),
heightDimension: .absolute(400)),
subitem: verticalGroup,
count: 1)
let section = NSCollectionLayoutSection(group: horizontalGroup)
section.orthogonalScrollingBehavior = .continuous
return section
default:
let item = NSCollectionLayoutItem(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)))
item.contentInsets = NSDirectionalEdgeInsets(top: 2, leading: 2, bottom: 2, trailing: 2)
let group = NSCollectionLayoutGroup.vertical(
layoutSize: NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0)),
subitem: item,
count: 1)
let section = NSCollectionLayoutSection(group: group)
return section
}
}
return layout
}
셀에 삭제 애니메이션과 같이 애니메이션 변화도 있도록 하기 위해선 Animated Data Source를 사용해야 한다. 기존 방법과는 다르게 SectionModel
이 AnimatableSectionModelType
를 채택해야 하고 Model
이 IndentifiableType
과 Equatable
프로토콜을 채택해야한다.