假设我有一个表格视图来展示产品。
这是我的viewModel:
var selectedObserver: AnyObserver<Product>
var state: Driver<Set<Product>>
var selectedSubject = PublishSubject<Product>()
self.selectedObserver = selectedSubject.asObserver()
self.state =
selectedSubject.asObservable()
.scan(Set()) { (acc: Set<Product>, item: Product) in
var acc = acc
if acc.contains(item) {
acc.remove(item)
} else {
acc.insert(item)
}
return acc
}
.startWith(Set())
.asDriver(onErrorJustReturn: Set())
self.isSelectedAll = Driver
.combineLatest(
self.state.map { $0.count },
envelope.map { $0.products.count })
.debug()
.map { $0.0 == $0.1 }
如你所见,每当我选择一个物体时,我会scan
进入可观察的状态,因此细胞可以观察状态的变化。
这是cell和viewModel之间的RxSwift绑定:
self.viewModel.deliveries
.drive(self.tableView.rx.items(cellIdentifier: DeliveryTableViewCellReusableIdentifier, cellType: DeliveryTableViewCell.self)) { (_, item, cell) in
cell.bind(to: self.viewModel.state, as: item)
cell.configureWith(product: item)
}
.disposed(by: disposeBag)
self.tableView.rx.modelSelected(Product.self)
.asDriver()
.drive(self.viewModel.selectedObserver)
.disposed(by: disposeBag)
func bind(to state: Driver<Set<Product>>, as item: Product) {
state.map { $0.contains(item) }
.drive(self.rx.isSelected)
.disposed(by: rx.reuseBag)
}
好吧,到目前为止一切顺利。
现在我的问题是如何选择所有操作,例如点击全选按钮,以便所有产品以某种方式 scan
进入州?
答案 0 :(得分:1)
当然,还有更多方法可以做到这一点。我想到的是single selection
与select all
有两个不同的事件,将它们统一在一个枚举中,例如。 SelectionEvent
,合并它们并将其传递给scan
,以便在扫描方法中区分它们。
粗略的例子,遵循你的代码:
var selectedObserver: AnyObserver<Product>
var state: Driver<Set<Product>>
var selectedSubject = PublishSubject<Product>()
var selectedAllSubject = PublishSubject<Product>() // Added
var selectedAllObserverObserver: AnyObserver<Void> // Added
self.selectedObserver = selectedSubject.asObserver()
self.selectedAllObserverObserver = selectedAllSubject.asObserver()
enum SelectionEvent {
case product(Product)
case all([Product])
}
self.state = Observable.of(
selectedSubject.map { SelectionEvent.product($0) },
// I figured envelope is observable containing all products.
selectedAllSubject.withLatestFrom(envelope.map { $0.products }).map { SelectionEvent.all($0) }
).merge()
.scan(Set()) { (acc: Set<Product>, event: SelectionEvent) in
var acc = acc
// now you can differentitate between events
switch event {
case .product:
if acc.contains(item) {
acc.remove(item)
} else {
acc.insert(item)
}
case .all(let all):
acc = all
}
return acc
}
.startWith(Set())
.asDriver(onErrorJustReturn: Set())
我希望这会有所帮助。