【iOS】RxCocoa,RxSwiftで複雑なTableViewを実装する


RxCocoa,RxSwiftsectionをつけたり複雑な実装をするときはRxTableViewDataSourceTypeを準拠したカスタムUITableViewDataSourceを作成する必要があります。

RxTableViewDataSourceTypeを準拠したUITableViewDataSourceの作成

準拠させる際にNSObjectも準拠させる必要があるところに注意

class CustomTableViewDataSource: NSObject, UITableViewDataSource, RxTableViewDataSourceType {
    // セクションを作る場合は多次元配列にする
    // Modelは任意のデータ型
    typealias Element = [[Model]]
    var items: Element = [[]]

    func tableView(_ tableView: UITableView, observedEvent: Event<[[Model]]>) {
        Binder(self) { dataSource, element in
            dataSource.items = element
            tableView.reloadData()
        }
        .on(observedEvent)
    }
}

セクションの作成

class CustomTableViewDataSource: NSObject, UITableViewDataSource, RxTableViewDataSourceType {
    // セクションの個数
    func numberOfSections(in tableView: UITableView) -> Int {
        return items.count
    }

    // セクション内のcellの個数
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items[section].count
    }
}

extension CustomTableView: UITableViewDelegate {
    // セクションに設定するViewを返す
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        return CustomTableHeaderView()
    }

    // セクションの高さを返す
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 30
    }
}

セクション内のcellの描画

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: R.reuseIdentifier.scheduleListCell.identifier, for: indexPath) as! CustomTableViewCell
        // ここでcellのinitととかを必要であればやる
        return cell
    }

スワイプでセルの削除などアクション有効にする

cellをスワイプしてアクションを表示させたい場合、canEditRowAtを有効にする必要がある。

func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
    return true
}

TableViewを描画する

前項までで作成したDataSourceを元にTableViewを描画する。

// Modelは任意のデータ
var items = BehaviorRelay<[[Model]]>(value: [])
let customDataSource = CustomTableViewDataSource()
private let disposeBag = DisposeBag()

private func observeList() {
    // itemsとcustomDataSourceを元にtableViewを描画する
    items
        .bind(to: tableView.rx.items(dataSource: customDataSource))
        .disposed(by: disposeBag)
}

// delegateを設定
private func setDelegate() {
    tableView.rx.setDelegate(self)
        .disposed(by: disposeBag)
}

// cellの選択
private func observeSelect() {
    tableView.rx.itemSelected.subscribe(onNext: { [weak self] indexPath in
        // 選択された時のアクションを記述
    }).disposed(by: disposeBag)
}