我怎样才能知道 table 视图是否被选为 Observable<Bool>?

How can I get whether a table view is selected as an Observable<Bool>?

在我的应用程序中,我有一个包含大量行的 table 视图。 table 视图由一个可观察对象填充。我正在使用 RxTableViewSectionedAnimatedDataSource.

使用 RxDataSources 来执行此操作

table 视图的行表示用户可以对其执行操作的某种项目。这意味着我希望某些按钮在行被 selected 时出现,并且我希望这些按钮在没有行被 selected 时消失。这些按钮是用户可以对项目执行的操作。

我想我可以观察 indexPathForSelectedRow 属性 并将其绑定到 button.rx.isHidden,像这样:

[actionButton1, actionButton2, actionButton3].forEach { (button) in
    button?.isHidden = true // they are always hidden initially
    self.tableView.rx.observe(IndexPath?.self, "indexPathForSelectedRow")
        .map { ([=12=] as? IndexPath) == nil } // [=12=] is a double optional, so I unwrap it like this
        .bind(to: button!.rx.isHidden)
        .disposed(by: disposeBag)
}

但是,当我 select 一个项目时,操作按钮根本不会出现。

我也尝试观察 indexPathsForSelectedRows,但结果相同。

然后我尝试分别订阅itemSelecteditemDeselected

[actionButton1, actionButton2, actionButton3].forEach { (button) in
    button?.isHidden = true

    self.tableView.rx.itemSelected.subscribe(onNext: {
        _ in
        button?.isHidden = false
    }).disposed(by: disposeBag)
    self.tableView.rx.itemDeselected.subscribe(onNext: {
        [weak self] _ in
        button?.isHidden = (self?.tableView.indexPathForSelectedRow ?? nil) == nil
    }).disposed(by: disposeBag)
}

这一次,当我 select 一行时,按钮正确显示。

然而,当可观察数据源发生变化时,selected 行被删除,导致 table 视图不再有任何 selected 行,操作按钮不会消失

当 table 视图没有任何 select 编辑的行时,如何使我的操作按钮消失?

请注意,我不关心 哪个 行是 select 编辑的。我只想知道 是否 任何行 selected。换句话说,只要语句 "the table view has at least one selected row" 从 true 变为 false,或从 false 变为 true,Observable<Bool> 就会发出一个新值。

如果你只使用 RxCocoa 应该这样做:

let itemIsSelected = Observable.merge(
    tableView.rx.itemSelected.map { _ in true },
    tableViewItems.map { _ in false } // this is the magic you are missing.
)
.startWith(false)

// a much easier way to handle your buttons' hidden state.
for buttonIsHidden in actionButtons.map({ [=10=].rx.isHidden }) {
    itemIsSelected
        .map { ![=10=] }
        .bind(to: buttonIsHidden)
        .disposed(by: disposeBag)
}

如果你使用的是 RxDataSources,解决方案更详细:

let itemSelected = tableView.rx.modelSelected(String.self) // or whatever the type is.
let itemIsSelected = Observable.merge(
    itemSelected.map { _ in true },
    tableViewItems.filter(if: itemSelected) { ![=11=].contains() }
        .map { _ in false }
)
.startWith(false)

for buttonIsHidden in actionButtons.map({ [=11=].rx.isHidden }) {
    itemIsSelected
        .map { ![=11=] }
        .bind(to: buttonIsHidden)
        .disposed(by: disposeBag)
}

以上使用了我的要点:https://gist.github.com/danielt1263/1a70c4f7b8960d06bd7f1bfa81802cc3

其中包含这个功能:

extension ObservableType {

    /// Filters the source observable sequence using a trigger observable sequence.
    /// Elements only go through the filter when the trigger has not completed and
    ///   its last element produces a true value from the pred. If either source or trigger error's, then the source errors.
    ///
    /// - Parameters:
    ///   - trigger: The sequence to compare with.
    ///   - pred: The predicate function to determine if the element should pass through.
    /// - Returns: An Observable of the same type that passed the filter test.
    func filter<O>(if trigger: O, _ pred: @escaping (Element, O.Element) -> Bool) -> Observable<Element> where O: ObservableType {
        return self.withLatestFrom(trigger) { ([=12=], ) }
            .filter { pred([=12=].0, [=12=].1) }
            .map { [=12=].0 }
    }
}