RxSwift学习-22-RxDataSources的使用

1,932 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情

  • 本文主要介绍下RxDataSources

对于RxSwift 也有很多拓展,我们比较常用的就是RxCocoa ,对于Tableview或者collectionView也有封装,里面还有其他的拓展,感兴趣的可以看看 RxSwiftCommunity) image.png

1. RxCocoa

我们正常写的话就是初始化,签订代理,实现代理。

image.png

那么使用RxCocoa怎么实现呢?我们展示的话

let items = Observable.just([

            "First Item",

            "Second Item",

            "Third Item"

        ])

        items

        .bind(to: tableView.rx.items) { (tableView, row, element) in

            let cell = tableView.dequeueReusableCell(withIdentifier: "UITableViewCell")!

            cell.textLabel?.text = "\(element) @ row \(row)"

            return cell


        }

        .disposed(by: disposeBag)

image.png

不需要签订协议,直接绑定到我们的tableview上,这里我们也可以自己注册cell

  • tableView.rx.items

        items

            .bind(to: tableView.rx.items(cellIdentifier: "Cell", cellType: UITableViewCell.self)) { (row, element, cell) in

               cell.textLabel?.text = "\(element) @ row \(row)"

            }

            .disposed(by: disposeBag)

对于我们tableView的一些代理事件也进行了封装

//点击事件

        tableView.rx.itemSelected

            .subscribe { indexPath in

                

                print("点击了\(indexPath.element!.row)")

            }.disposed(by: disposeBag)

image.png

但是我们对于有的比如返回tableView的行高等,就没有封装,我们这时候可以设置delegate来实现

tableView.rx.setDelegate(self)

            .disposed(by: disposeBag)

我们实现具体代理

image.png

对于一些复杂的分组等,我们可以使用 RxDataSources

2. RxDataSources

我们先看下简单的分组使用首先我们看下sectionModel

image.png

当然我们也可以自己自定义

struct MySection {

    var header: String

    var items: [Item]

}


extension MySection : AnimatableSectionModelType {

    typealias Item = Int

    var identity: String {

        return header

    }

    init(original: MySection, items: [Item]) {

        self = original

        self.items = items

    }

}

我们创建datasource

tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")

        let dataSource1 = RxTableViewSectionedAnimatedDataSource<MySection>(

            configureCell: { ds, tv, _, item in

                let cell = tv.dequeueReusableCell(withIdentifier: "Cell") ?? UITableViewCell(style: .default, reuseIdentifier: "Cell")

                cell.textLabel?.text = "Item \(item)"

                return cell

            },

            titleForHeaderInSection: { ds, index in

                return ds.sectionModels[index].header

            }

        )

        self.dataSource = dataSource1

        let sections = [

            MySection(header: "First section", items: [

                1,

                2

            ]),

            MySection(header: "Second section", items: [

                3,

                4

            ])

        ]


        Observable.just(sections)

            .bind(to: tableView.rx.items(dataSource: dataSource1))

            .disposed(by: disposeBag)

运行效果

image.png

  • 不同数据源的分组
enum MultipleSectionModel {

    case ImageProvidableSection(title: String, items: [SectionItem])

    case ToggleableSection(title: String, items: [SectionItem])

    case StepperableSection(title: String, items: [SectionItem])

}



enum SectionItem {

    case ImageSectionItem(image: UIImage, title: String)

    case ToggleableSectionItem(title: String, enabled: Bool)

    case StepperSectionItem(title: String)

}


extension MultipleSectionModel: SectionModelType {

    typealias Item = SectionItem

    

    var items: [SectionItem] {

        switch  self {

        case .ImageProvidableSection(title: _, items: let items):

            return items.map { $0 }

        case .StepperableSection(title: _, items: let items):

            return items.map { $0 }

        case .ToggleableSection(title: _, items: let items):

            return items.map { $0 }

        }

    }

    

    init(original: MultipleSectionModel, items: [Item]) {

        switch original {

        case let .ImageProvidableSection(title: title, items: _):

            self = .ImageProvidableSection(title: title, items: items)

        case let .StepperableSection(title, _):

            self = .StepperableSection(title: title, items: items)

        case let .ToggleableSection(title, _):

            self = .ToggleableSection(title: title, items: items)

        }

    }

}

这里使用枚举展示定义不同的cell样式,和Item。我们处理数据dataSource

static func dataSource() -> RxTableViewSectionedReloadDataSource<MultipleSectionModel> {

        return RxTableViewSectionedReloadDataSource<MultipleSectionModel>(

            configureCell: { dataSource, table, idxPath, _ in

                switch dataSource[idxPath] {

                case let .ImageSectionItem(image, title):

                    let cell: ImageTitleTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath)

                    cell.configure(image: image, title: title)

                    return cell

                case let .StepperSectionItem(title):

                    let cell: TitleSteperTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath)

                    cell.configure(title: title)

                    return cell

                case let .ToggleableSectionItem(title, enabled):

                    let cell: TitleSwitchTableViewCell = table.dequeueReusableCell(forIndexPath: idxPath)

                    cell.configure(title: title, isEnabled: enabled)

                    return cell

                }

            },

            titleForHeaderInSection: { dataSource, index in

                let section = dataSource[index]

                return section.title

            }

        )

    }

}

我们tableView绑定我们datasource

let sections: [MultipleSectionModel] = [

            .ImageProvidableSection(title: "Section 1",

                items: [.ImageSectionItem(image: UIImage(named: "settings")!, title: "General")]),

            .ToggleableSection(title: "Section 2",

                items: [.ToggleableSectionItem(title: "On", enabled: true),.ToggleableSectionItem(title: "Off", enabled: false)]),

            .StepperableSection(title: "Section 3",

                items: [.StepperSectionItem(title: "1"),.StepperSectionItem(title: "2"),.ToggleableSectionItem(title: "On", enabled: true)])

        ]

        

        let dataSource = ViewController.dataSource()

        

        Observable.just(sections)

            .bind(to: tableView.rx.items(dataSource: dataSource))

            .disposed(by: disposeBag)

运行效果

image.png

3. 对MJ封装

我们通常也会对上拉刷新和下拉加载更多进行分装,把我们刷新的事件转换为序列,并提供绑定。

extension Reactive where Base: UITableView {

    /// 刷新

     var refresh: ControlEvent<RefreshType> {

        let source = Observable<RefreshType>.create { observer in

            if base.mj_header == nil {

                base.mj_header = MJRefreshNormalHeader(refreshingBlock: {

                    observer.on(.next(.refresh))

                })

            }

            

            if base.mj_footer == nil {

                base.mj_footer = MJRefreshAutoNormalFooter(refreshingBlock: {

                    observer.on(.next(.loadMore))

                })

            }

            

            return Disposables.create()

        }

        

        return ControlEvent(events: source)

    }

    

    /// 停止下拉刷新

     var endRefresh: Binder<(RefreshType, Bool)> {

        Binder(base) { control, data in

            switch data.0 {

            case .refresh:

                control.mj_header?.endRefreshing()

                if data.1 {

                    control.mj_footer?.endRefreshingWithNoMoreData()

                } else {

                    control.mj_footer?.resetNoMoreData()

                }

            case .loadMore:

                control.mj_footer?.endRefreshing()

                if data.1 {

                    control.mj_footer?.endRefreshingWithNoMoreData()

                }

            default:

                if data.1 {

                    control.mj_footer?.endRefreshingWithNoMoreData()

                }

            }

            

        }

    }

}

其中RefreshType我们定义为刷新类型

enum RefreshType {

    case none

    case refresh

    case loadMore

}

4. 总结

对于一些简单的展示类的cell比较适合,但是对于一些负责的tableView,拓展性不是很好,比如cell高度的设定,当然我们自己也可以拓展。看自己需要,灵活运用。