RxSwift+MVVM项目实战-多分组UITableView结合RxDataSources的使用

简介: RxSwift+MVVM项目实战-多分组UITableView结合RxDataSources的使用

主要介绍RxSwift+MVVM结合RxDataSources实现多分组的UITableView,实现效果如图(文末附源码):


1. RxDataSources简介

RxDataSourcesRxSwiftUITableView以及UICollectionView的数据源的进一步封装;

安装方式1:CocoaPods

# https://github.com/RxSwiftCommunity/RxDataSources
pod 'RxDataSources'

安装方式2:Carthage


github "RxSwiftCommunity/RxDataSources" ~> 5.0.0

安装方式3:Swift Package Manager

import PackageDescription
let package = Package(
    name: "SampleProject",
    dependencies: [
        .package(url: "https://github.com/RxSwiftCommunity/RxDataSources.git", from: "5.0.0")
    ]
)

2. RxSwift+MVVM分层设计

项目目录结构如图:


2.1 MuchGroupListModel

主要用于存储数据,保存从网络请求中获取到的数据源;


struct MuchGroupListModel: HandyJSON {
    var name: String? //用于显示名称
    var urls: MuchGroupListUrlModel? //图片模型-获取图片名称
    var type: Int? //cell的显示类型
    var desc: String? //用于显示描述信息
    init() { }
}
struct MuchGroupListUrlModel: HandyJSON {
    var pic: String?
    init() { }
}

2.2 View

MuchGroupBannerCell:绑定ViewModel传递过来的数据到UI控件上;

class MuchGroupBannerCell: UITableViewCell {
    var disposeBag = DisposeBag()
    let openSubjuect = PublishSubject<Void>()
    ...
    override func prepareForReuse() {
        super.prepareForReuse()
        disposeBag = DisposeBag()
    }
    func bind(to viewModel: MuchGroupBannerViewModel) {
        viewModel.image.bind(to: picImageView.rx.image).disposed(by: disposeBag)
        viewModel.title.bind(to: nickNameLabel.rx.text).disposed(by: disposeBag)
        viewModel.detail.bind(to: detailLabel.rx.text).disposed(by: disposeBag)
        openButton.rx.tap.bind(to: openSubjuect).disposed(by: disposeBag)
    }
    ...
}

MuchGroupLiveCell绑定ViewModel传递过来的数据到UI控件上;

class MuchGroupLiveCell: UITableViewCell {
    var disposeBag = DisposeBag()
    let openSubjuect = PublishSubject<Void>()
     ...
    override func prepareForReuse() {
        super.prepareForReuse()
        disposeBag = DisposeBag()
    }
    func bind(to viewModel: MuchGroupLiveViewModel) {
        viewModel.title.bind(to: nickNameLabel.rx.text).disposed(by: disposeBag)
        viewModel.detail.bind(to: detailLabel.rx.attributedText).disposed(by: disposeBag)
        openButton.rx.tap.bind(to: openSubjuect).disposed(by: disposeBag)
    }
     ...
}


2.3 Controller

绑定ViewModel回调过来的数据,并绑定到UI界面上,以及做出对应的响应;

private func bindToViewModel() {
    let output = viewModel.transform(input: MuchGroupViewModel.Input(refresh: Observable.just(()),
                                           headerRefresh: tableView.mj_header!.rx.glt_refreshing.asObservable(),
                                           footerRefresh: tableView.mj_footer!.rx.glt_refreshing.asObservable()))
    let dataSource = LTTableViewSectionedReloadDataSource<MuchGroupSection> {[unowned self] (dataSource, tableView, indexPath, item) -> UITableViewCell in
        switch item {
        case .banner(let viewModel):
            let cell: MuchGroupBannerCell = self.cellWithTableView(tableView)
            //绑定
            cell.bind(to: viewModel)
            //按钮点击事件
            cell.openSubjuect.subscribe {[weak self] (_) in
                self?.openEvent(viewModel.model, indexPath)
            }.disposed(by: cell.disposeBag)
            return cell
        case .live(let viewModel):
            let cell: MuchGroupLiveCell = self.cellWithTableView(tableView)
            //绑定
            cell.bind(to: viewModel)
            //按钮点击事件
            cell.openSubjuect.subscribe {[weak self] (_) in
                self?.openEvent(viewModel.model, indexPath)
            }.disposed(by: cell.disposeBag)
            return cell
        }
    }
    output.items.bind(to: tableView.rx.items(dataSource: dataSource)).disposed(by: disposeBag)
    output.endRefreshing.bind(to: tableView.rx.endRefreshing).disposed(by: disposeBag)
    dataSource.reloadEnded.subscribe { (_) in
        Logger("reloadData完毕")
    }.disposed(by: disposeBag)
    tableView.rx.itemSelected.subscribe {[weak self] (value) in
        if let indexPath = value.element {
            self?.tableView.deselectRow(at: indexPath, animated: true)
        } 
        self?.navigationController?.pushViewController(MuchGroupViewController(), animated: true)
    }.disposed(by: disposeBag)
    refreshItem.rx.tap.subscribe {[weak self] (_) in
        self?.tableView.mj_header?.beginRefreshing()
    }.disposed(by: disposeBag)
    tableView.rx.setDelegate(self).disposed(by: disposeBag)
}

2.4 MuchGroupSection

MuchGroupSection:决定将来分组的类型,bannerlive分别对应了两种不同样式的cell

MuchGroupSectionItem:根据分组类型用于每个cell展示的ViewModel

MuchGroupSection:实现RxDataSources用于提供数据源支持必须遵守的协议;

  •  

enum MuchGroupSection {//决定将来分组的类型
    case banner(title: String, items: [MuchGroupSectionItem])
    case live(title: String, items: [MuchGroupSectionItem])
}
enum MuchGroupSectionItem {//根据分组类型用于每个cell展示的viewModel
    case banner(cellViewModel: MuchGroupBannerViewModel)
    case live(cellViewModel: MuchGroupLiveViewModel)
}
//实现RxDataSources用于提供数据源支持必须遵守的协议SectionModelType
extension MuchGroupSection: SectionModelType {
    typealias Item = MuchGroupSectionItem
    var items: [MuchGroupSectionItem] {
        switch self {
        case .banner(_, let items):
            return items
        case .live(_, let items):
            return items
        }
    }
    init(original: MuchGroupSection, items: [MuchGroupSectionItem]) {
        self = original
    }
}

2.5 ViewModel

MuchGroupBannerViewModel:提供用于bannerCell上的绑定数据源;


struct MuchGroupBannerViewModel {
    let title = BehaviorRelay<String?>(value: nil)
    let detail = BehaviorRelay<String?>(value: nil)
    let image = BehaviorRelay<UIImage?>(value: nil)
    let model: MuchGroupListModel?
    init(model: MuchGroupListModel?) {
        ...
    }
}

MuchGroupLiveViewModel:提供用于liveCell上的绑定数据源;

struct MuchGroupLiveViewModel {
    var title = BehaviorRelay<String?>(value: nil)
    var detail = BehaviorRelay<NSAttributedString?>(value: nil)
    var model:  MuchGroupListModel?
    init(model: MuchGroupListModel?) {
        ...
    }
}

MuchGroupViewModel:接收传递过来的事件,经过处理后,回调给外界做出对应处理响应;

class MuchGroupViewModel {
    ...
    struct Input {
        let refresh: Observable<Void>
        let headerRefresh: Observable<Void>
        let footerRefresh: Observable<Void>
    }
    struct Output {
        let items: BehaviorRelay<[MuchGroupSection]>
        let endRefreshing: PublishRelay<LTRefreshEndState>
    }
    func transform(input: Input) -> Output {
        ...
    }
}

下一篇将为您介绍RxDataSources结合MJRefresh的具体使用,建议结合本篇一起查看;


分享收藏划线


相关文章
|
存储 数据安全/隐私保护
RxSwift+MVVM项目实战-登录功能实现
RxSwift+MVVM项目实战-登录功能实现
255 0
|
6月前
|
JavaScript 小程序 Android开发
【经验分享】如何实现自定义的actionSheet组件
【经验分享】如何实现自定义的actionSheet组件
123 6
RxSwift+MVVM项目实战-单分组UITableView的使用
RxSwift+MVVM项目实战-单分组UITableView的使用
250 0
RxSwift+MVVM项目实战-多分组UITableView+RxDataSources+MJRefresh的使用
RxSwift+MVVM项目实战-多分组UITableView+RxDataSources+MJRefresh的使用
148 0
|
存储
RxSwift+MVVM项目实战-单分组UITableView添加、删除、移动功能
RxSwift+MVVM项目实战-单分组UITableView添加、删除、移动功能
149 0
|
JSON HandyJSON Swift
RxSwift+MVVM项目实战-多分组TableView+MJRefresh+RxAlamofire+HandyJSON的使用
RxSwift+MVVM项目实战-多分组TableView+MJRefresh+RxAlamofire+HandyJSON的使用
334 0
|
存储 前端开发
RxSwift+MVVM项目实战-MVVM架构介绍以及实战初体验
RxSwift+MVVM项目实战-MVVM架构介绍以及实战初体验
441 0
|
前端开发
[译] 实用的 MVVM 和 RxSwift
今天我们将使用 RxSwift 实现 MVVM 设计模式。对于那些刚接触 RxSwift 的人,我 在这里 专门做了一个部分来介绍。
1372 0
|
前端开发 JavaScript Android开发
|
前端开发 JavaScript Android开发