はじめに
RxSwiftでCollectionViewを使用する際のバインド方法がいくつかあることを知り、簡単にまとめてみました。
開発環境
Xcode 13.3
Swift 5.6
RxSwift 6.5.0
UICollectionViewのbindについて
バインドパターン1
items.bind(to: collectionView.rx.items)
でデータをバインド
indexPathをIndexPath(row: row, section: 0)
としてセルを生成して返す
let items = Observable.just([1, 2, 3])
items.bind(to: collectionView.rx.items) { (collectionView, row, element) in
let indexPath = IndexPath(row: row, section: 0)
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! NumberCell
cell.value?.text = "\(element) @ \(row)"
return cell
}.disposed(by: disposeBag)
バインドパターン2
items.bind(to: collectionView.rx.items(cellIdentifier: "Cell", cellType: NumberCell.self))
でCellを指定しながらデータをバインド
let items = Observable.just([1, 2, 3])
items.bind(to: collectionView.rx.items(cellIdentifier: "Cell", cellType: NumberCell.self)) { (row, element, cell) in
cell.value?.text = "\(element) @ \(row)"
}.disposed(by: disposeBag)
バインドパターン3
変換を実行するために使用されるカスタムデータを使用して、items.bind(to: collectionView.rx.items(dataSource: dataSource))
でバインド
let dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel<String, Double>>()
let items = Observable.just([
SectionModel(model: "First section", items: [1.0, 2.0, 3.0]),
SectionModel(model: "Second section", items: [1.0, 2.0, 3.0]),
SectionModel(model: "Third section", items: [1.0, 2.0, 3.0])])
dataSource.configureCell = { (dataSource, cv, indexPath, element) in
let cell = cv.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! NumberCell
cell.value?.text = "\(element) @ row \(indexPath.row)"
return cell
}
items
.bind(to: collectionView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
セル選択時の処理
collectionView(_:didSelectItemAtIndexPath:)
と同じ
collectionView.rx.itemSelected
.subscribe(onNext: { [unowned self] indexPath in
self.collectionView.deselectItem(at: indexPath, animated: true)
// ここに追加
})
.disposed(by: disposeBag)
delegateの設定
通常のデリゲートとリアクティブデリゲートを併用できるようになる
UICollectionViewDelegate
,UICollectionViewDelegateFlowLayout
public func setDelegate(_ delegate: UIScrollViewDelegate) -> Disposable {
return RxScrollViewDelegateProxy.installForwardDelegate(delegate, retainDelegate: false, onProxyForObject: self.base)
}
UICollectionViewDataSource
public func setDataSource(_ dataSource: UICollectionViewDataSource) -> Disposable {
RxCollectionViewDataSourceProxy.installForwardDelegate(dataSource, retainDelegate: false, onProxyForObject: self.base)
}
おわりに
整理してみると大したことではなさそうなので、基本的には1番分かりやすい(collectionView(_:cellForItemAt:)
に近い)パターン1で実装していけば良いかと思いました。
参照