RxDataSources tableView 具有来自一个 API 源的多个部分
RxDataSources tableView with multiple sections from one API source
目前我们的 API 请求使用 Rx。我们如何使用它的一个例子是:
let orderRxService = OrderRxService.listAsShop(shopId, status: .active)
.repeatRequest(delay: 4)
.observeOn(MainScheduler.instance)
.subscribe( onNext: { [weak self] orders in
self?.orders = orders
self?.tableView.reloadData()
})
.disposed(by: disposeBag)
这会获取状态为 .active
的给定 shopId
的所有订单。每次更新时,本地 orders
对象都会被替换并重新加载 tableView。
这将重新加载我们想要避免的整个 tableView。我现在正在研究 RxDataSources,但无法真正弄清楚如何让它工作。
一个Order
对象有另一个属性currentStatus
,可以是3个不同的值。
我们有一个包含 3 个不同部分的 tableView,每个部分显示 currentStatus
.
的所有订单
这应该如何在 RxDataSources 中实现?理想情况下是将它绑定到我之前展示的服务 (OrderRxService.....subscribe()..
)。
我现在要设置 RxDataSources 类型的是:
extension Order: IdentifiableType, Equatable {
public typealias Identity = String
public var identity: String {
return String(id)
}
public static func == (lhs: Order, rhs: Order) -> Bool {
return (lhs.timeCreated ?? 0) > (rhs.timeCreated ?? 0)
}
}
struct OrdersSection {
var header: String
var orders: [Order]
}
extension OrdersSection: AnimatableSectionModelType {
typealias Item = Order
typealias Identity = String
var identity: String {
return header
}
var items: [Item] {
set {
orders = items
}
get {
return orders
}
}
init(original: OrdersSection, items: [Order]) {
self = original
self.items = items
}
}
我试图让它工作的是:
// I tried to make our local orders a Variable (I don't like this between-step and would like this to be just [Order]).
var orders: Variable<[Order]> = Variable([])
fun viewDidLoad() {
super.viewDidLoad()
// Then I set the local orders-variable's value to the new value coming from our Rx service.
let orderRxDisposable: Disposable = OrderRxService.listAsShop(shopId, status: .active)
.repeatRequest(delay: 4)
.observeOn(MainScheduler.instance)
.map { [=13=].items }.subscribe( onNext: { [weak self] orders in
self?.orders.value = orders
})
// Here I setup the dataSource
let dataSource = RxTableViewSectionedAnimatedDataSource<OrdersSection>(
configureCell: { ds, tv, ip, item in
let cell = tv.dequeueReusableCell(withIdentifier: "OrderCell", for: ip) as! OrderCell
cell.addContent(item, tableView: tv, viewController: self, spotDelegate: self)
return cell
},
titleForHeaderInSection: { ds, ip in
return ds.sectionModels[ip].header
}
)
// Here I set up the three different sections.
self.orders.asObservable().observeOn(MainScheduler.instance)
.map { o in
o.filter { [=13=].currentStatus == .status_one }
}
.map { [OrdersSection(header: "Status one", orders: [=13=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
self.orders.asObservable().observeOn(MainScheduler.instance)
.map { o in
o.filter { [=13=].currentStatus == .status_two }
}
.map { [OrdersSection(header: "Status two", orders: [=13=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
self.orders.asObservable().observeOn(MainScheduler.instance)
.map { o in
o.filter { [=13=].currentStatus == .status_three }
}
.map { [OrdersSection(header: "Status three", orders: [=13=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
}
可能有不同的方面可以改进。例如 Variable<[Order]>
我想只是 [Order]
。
而不是让这个可观察,是否可以完全跳过并通过观察我们的 OrderRxService 创建三个不同的部分?
是否可以像这样:
OrderRxService.listAsshop(shopId, status: .active).observeOn(MainScheduler.instance)
// First section
.map { o in
o.filter { [=14=].status == .status_one }
}
.map { [OrdersSection(header: "Status one", orders: [=14=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
// Second section
.map { o in
o.filter { [=14=].status == .status_two }
}
.map { [OrdersSection(header: "Status two", orders: [=14=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
// Etc...
感谢您的帮助!
您可以像这样创建一个模型:
enum SectionModel {
case SectionOne(items: [SectionItem])
case SectionTwo(items: [SectionItem])
case SectionThree(items: [SectionItem])
}
enum SectionItem {
case StatusOne()
case StatusTwo()
case StatusThree()
}
extension SectionModel: SectionModelType {
typealias Item = SectionItem
var items: [SectionItem] {
switch self {
case .SectionOne(items: let items):
return items.map { [=10=] }
case .SectionTwo(items: let items):
return items.map { [=10=] }
case.SectionThree(items: let items):
return items.map { [=10=] }
}
}
init(original: SectionModel, items: [Item]) {
switch original {
case .SectionOne(items: _):
self = .SectionOne(items: items)
case .SectionTwo(items: _):
self = .SectionTwo(items: items)
case .SectionThree(items: _):
self = .SectionThree(items: items)
}
}
}
并处理数据源中的不同项目
dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel>(configureCell: { (datasource, collectionView, indexPath, _) in
switch datasource[indexPath] {
case .StatusOne:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellOne, for: indexPath)!
// do stuff
return cell
case .StatusTwo:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellTwo, for: indexPath)!
// do stuff
return cell
case .StatusThree:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellThree, for: indexPath)!
// do stuff
return cell
}
})
然后将您的订单映射到 SectionModel
的 SectionItem
并将其绑定到数据源
您不需要 map->bind->map->bind...您可以像这样简单地在一个 'map' 中处理所有内容:
OrderRxService.listAsshop(shopId, status: .active).observeOn(MainScheduler.instance)
.map { orders in
let sections: [OrdersSection] = []
sections.append(OrdersSection(header: "Status one", orders: orders.filter { [=10=].status == .status_one })
sections.append(OrdersSection(header: "Status two", orders: orders.filter { [=10=].status == .status_two })
sections.append(OrdersSection(header: "Status three", orders: orders.filter { [=10=].status == .status_three })
return sections
}
.bind(to: self.tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
此外,如果您经常使用 RxSwift/RxDataSources/etc 并且需要指导,加入 RxSwift Slack 频道是一个很好的资源:
Invite to RxSwift Slack
目前我们的 API 请求使用 Rx。我们如何使用它的一个例子是:
let orderRxService = OrderRxService.listAsShop(shopId, status: .active)
.repeatRequest(delay: 4)
.observeOn(MainScheduler.instance)
.subscribe( onNext: { [weak self] orders in
self?.orders = orders
self?.tableView.reloadData()
})
.disposed(by: disposeBag)
这会获取状态为 .active
的给定 shopId
的所有订单。每次更新时,本地 orders
对象都会被替换并重新加载 tableView。
这将重新加载我们想要避免的整个 tableView。我现在正在研究 RxDataSources,但无法真正弄清楚如何让它工作。
一个Order
对象有另一个属性currentStatus
,可以是3个不同的值。
我们有一个包含 3 个不同部分的 tableView,每个部分显示 currentStatus
.
这应该如何在 RxDataSources 中实现?理想情况下是将它绑定到我之前展示的服务 (OrderRxService.....subscribe()..
)。
我现在要设置 RxDataSources 类型的是:
extension Order: IdentifiableType, Equatable {
public typealias Identity = String
public var identity: String {
return String(id)
}
public static func == (lhs: Order, rhs: Order) -> Bool {
return (lhs.timeCreated ?? 0) > (rhs.timeCreated ?? 0)
}
}
struct OrdersSection {
var header: String
var orders: [Order]
}
extension OrdersSection: AnimatableSectionModelType {
typealias Item = Order
typealias Identity = String
var identity: String {
return header
}
var items: [Item] {
set {
orders = items
}
get {
return orders
}
}
init(original: OrdersSection, items: [Order]) {
self = original
self.items = items
}
}
我试图让它工作的是:
// I tried to make our local orders a Variable (I don't like this between-step and would like this to be just [Order]).
var orders: Variable<[Order]> = Variable([])
fun viewDidLoad() {
super.viewDidLoad()
// Then I set the local orders-variable's value to the new value coming from our Rx service.
let orderRxDisposable: Disposable = OrderRxService.listAsShop(shopId, status: .active)
.repeatRequest(delay: 4)
.observeOn(MainScheduler.instance)
.map { [=13=].items }.subscribe( onNext: { [weak self] orders in
self?.orders.value = orders
})
// Here I setup the dataSource
let dataSource = RxTableViewSectionedAnimatedDataSource<OrdersSection>(
configureCell: { ds, tv, ip, item in
let cell = tv.dequeueReusableCell(withIdentifier: "OrderCell", for: ip) as! OrderCell
cell.addContent(item, tableView: tv, viewController: self, spotDelegate: self)
return cell
},
titleForHeaderInSection: { ds, ip in
return ds.sectionModels[ip].header
}
)
// Here I set up the three different sections.
self.orders.asObservable().observeOn(MainScheduler.instance)
.map { o in
o.filter { [=13=].currentStatus == .status_one }
}
.map { [OrdersSection(header: "Status one", orders: [=13=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
self.orders.asObservable().observeOn(MainScheduler.instance)
.map { o in
o.filter { [=13=].currentStatus == .status_two }
}
.map { [OrdersSection(header: "Status two", orders: [=13=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
self.orders.asObservable().observeOn(MainScheduler.instance)
.map { o in
o.filter { [=13=].currentStatus == .status_three }
}
.map { [OrdersSection(header: "Status three", orders: [=13=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
}
可能有不同的方面可以改进。例如 Variable<[Order]>
我想只是 [Order]
。
而不是让这个可观察,是否可以完全跳过并通过观察我们的 OrderRxService 创建三个不同的部分?
是否可以像这样:
OrderRxService.listAsshop(shopId, status: .active).observeOn(MainScheduler.instance)
// First section
.map { o in
o.filter { [=14=].status == .status_one }
}
.map { [OrdersSection(header: "Status one", orders: [=14=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
// Second section
.map { o in
o.filter { [=14=].status == .status_two }
}
.map { [OrdersSection(header: "Status two", orders: [=14=])] }
.bind(to: self.tableView.rx.items(dataSource: dataSource))
// Etc...
感谢您的帮助!
您可以像这样创建一个模型:
enum SectionModel {
case SectionOne(items: [SectionItem])
case SectionTwo(items: [SectionItem])
case SectionThree(items: [SectionItem])
}
enum SectionItem {
case StatusOne()
case StatusTwo()
case StatusThree()
}
extension SectionModel: SectionModelType {
typealias Item = SectionItem
var items: [SectionItem] {
switch self {
case .SectionOne(items: let items):
return items.map { [=10=] }
case .SectionTwo(items: let items):
return items.map { [=10=] }
case.SectionThree(items: let items):
return items.map { [=10=] }
}
}
init(original: SectionModel, items: [Item]) {
switch original {
case .SectionOne(items: _):
self = .SectionOne(items: items)
case .SectionTwo(items: _):
self = .SectionTwo(items: items)
case .SectionThree(items: _):
self = .SectionThree(items: items)
}
}
}
并处理数据源中的不同项目
dataSource = RxCollectionViewSectionedReloadDataSource<SectionModel>(configureCell: { (datasource, collectionView, indexPath, _) in
switch datasource[indexPath] {
case .StatusOne:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellOne, for: indexPath)!
// do stuff
return cell
case .StatusTwo:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellTwo, for: indexPath)!
// do stuff
return cell
case .StatusThree:
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: R.reuseIdentifier.statusCellThree, for: indexPath)!
// do stuff
return cell
}
})
然后将您的订单映射到 SectionModel
的 SectionItem
并将其绑定到数据源
您不需要 map->bind->map->bind...您可以像这样简单地在一个 'map' 中处理所有内容:
OrderRxService.listAsshop(shopId, status: .active).observeOn(MainScheduler.instance)
.map { orders in
let sections: [OrdersSection] = []
sections.append(OrdersSection(header: "Status one", orders: orders.filter { [=10=].status == .status_one })
sections.append(OrdersSection(header: "Status two", orders: orders.filter { [=10=].status == .status_two })
sections.append(OrdersSection(header: "Status three", orders: orders.filter { [=10=].status == .status_three })
return sections
}
.bind(to: self.tableView.rx.items(dataSource: dataSource))
.disposed(by: disposeBag)
此外,如果您经常使用 RxSwift/RxDataSources/etc 并且需要指导,加入 RxSwift Slack 频道是一个很好的资源: Invite to RxSwift Slack