使用RxSwift开发tableView
- 确定数据类型 以及绑定cell
这里数据类型都需要通过 SectionModel 来包装 一个SectionModel 对象对应一个分区的数据。configCell这个闭包是用来配置cell的,每次数据模型变动都会重新刷新tableView。 这里数据类型一定要包装成sectionModel类型。不然会有问题
lazy var dataSource : RxTableViewSectionedReloadDataSource<SectionModel<String,MenuModel>> = {
let dataSource = RxTableViewSectionedReloadDataSource<SectionModel<String,MenuModel>>(configureCell: { source, tableView, indexPath, item in
let cell = tableView.dequeueReusableCell(withIdentifier: "MenuCell", for: indexPath) as! MenuCell
cell.model = item
cell.focusSubject.subscribe { (event) in
guard let ele = event.element else { return }
let sectionModels = self.dataSource.sectionModels.first
guard let index = self.tableView.indexPath(for: cell) else { return }
if index.row == 0 && index.section == 0 { return }
self.tableView.moveRow(at: index, to: IndexPath.init(row: 0, section: 1))
}.disposed(by: self.bag)
return cell
},canMoveRowAtIndexPath:{ (dataSource,indexPath) -> Bool in
return true
})
return dataSource
}()
/*
初始化dataSource对象,保存configureCell
*/
public init(
configureCell: @escaping ConfigureCell,
titleForHeaderInSection: @escaping TitleForHeaderInSection = { _, _ in nil },
titleForFooterInSection: @escaping TitleForFooterInSection = { _, _ in nil },
canEditRowAtIndexPath: @escaping CanEditRowAtIndexPath = { _, _ in false },
canMoveRowAtIndexPath: @escaping CanMoveRowAtIndexPath = { _, _ in false },
sectionIndexTitles: @escaping SectionIndexTitles = { _ in nil },
sectionForSectionIndexTitle: @escaping SectionForSectionIndexTitle = { _, _, index in index }
) {
self.configureCell = configureCell
self.titleForHeaderInSection = titleForHeaderInSection
self.titleForFooterInSection = titleForFooterInSection
self.canEditRowAtIndexPath = canEditRowAtIndexPath
self.canMoveRowAtIndexPath = canMoveRowAtIndexPath
self.sectionIndexTitles = sectionIndexTitles
self.sectionForSectionIndexTitle = sectionForSectionIndexTitle
}
/*
在UITableViewDataSource中得到configureCell的返回值
*/
open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
precondition(indexPath.item < _sectionModels[indexPath.section].items.count)
return configureCell(self, tableView, indexPath, self[indexPath])
}
- 绑定viewModel 的数据源
监听viewModel.menuModels的变化和tableView的数据源进行绑定。当网络请求完成的时候,就会触发tableView的reloadData
viewModel
.menuModels
.asObservable()
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by:bag)
/*
tableView.rx.items(dataSource: dataSource
*/
public func items<DataSource: RxTableViewDataSourceType & UITableViewDataSource,
O: ObservableType>(dataSource: DataSource) -> (_ source: O) -> Disposable
where DataSource.Element == O.E {
return { source in
_ = self.delegate
// dataSource 开始订阅数据代码
return source.subscribeProxyDataSource(ofObject: self.base, dataSource: dataSource as UITableViewDataSource, retainDataSource: true) { [weak tableView = self.base] (_: RxTableViewDataSourceProxy, event) -> Void in
guard let tableView = tableView else {
return
}
dataSource.tableView(tableView, observedEvent: event)
}
func subscribeProxyDataSource<DelegateProxy: DelegateProxyType>(ofObject object: DelegateProxy.ParentObject, dataSource: DelegateProxy.Delegate, retainDataSource: Bool, binding: @escaping (DelegateProxy, Event<E>) -> Void)
-> Disposable
where DelegateProxy.ParentObject: UIView {
let proxy = DelegateProxy.proxy(for: object)
let unregisterDelegate = DelegateProxy.installForwardDelegate(dataSource, retainDelegate: retainDataSource, onProxyForObject: object)
// this is needed to flush any delayed old state (https://github.com/RxSwiftCommunity/RxDataSources/pull/75)
object.layoutIfNeeded()
let subscription = self.asObservable()
.observeOn(MainScheduler())
.catchError { error in
bindingError(error)
return Observable.empty()
}
// source can never end, otherwise it would release the subscriber, and deallocate the data source
.concat(Observable.never())
.takeUntil(object.rx.deallocated)
.subscribe { [weak object] (event: Event<E>) in
if let object = object {
assert(proxy === DelegateProxy.currentDelegate(for: object), "Proxy changed from the time it was first set.\nOriginal: \(proxy)\nExisting: \(String(describing: DelegateProxy.currentDelegate(for: object)))")
}
binding(proxy, event)
switch event {
case .error(let error):
bindingError(error)
unregisterDelegate.dispose()
case .completed:
unregisterDelegate.dispose()
default:
break
}
}
return Disposables.create { [weak object] in
subscription.dispose()
object?.layoutIfNeeded()
unregisterDelegate.dispose()
}
}
/*
bind(to:) 调取之后返回的是
*/
public func bind<R>(to binder: (Self) -> R) -> R {
// 将数据源和tableView 之间进行绑定
return binder(self)
}
}
}
- tableView各种事件的监听和配置
tableView的sectionTitle,cellSelect之类都可以通过绑定的方法来监听。
tableView.rx.itemSelected.subscribe { event in
guard let index = event.element else { return }
let sectionModel = self.dataSource.sectionModels[index.section]
let model = sectionModel.items[index.row]
print("选中了 " + model.name)
}.disposed(by: bag)