主要介绍RxSwift+MVVM
结合RxDataSources
实现多分组的UITableView
,实现效果如图(文末附源码):
1. RxDataSources简介
RxDataSources
是RxSwift
对UITableView
以及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
:决定将来分组的类型,banner
和live
分别对应了两种不同样式的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
的具体使用,建议结合本篇一起查看;
分享收藏划线