RxSwift如何有条件地控制按钮何时发出点击信号?

6

我想防止我的UIButtons在某个控制流指示准备好之前发出RX tap事件。如果控制流恢复到未准备好状态,我希望按钮再次被禁用。控制序列是一个ReplaySubject,并且始终具有值。

我已经尝试了skipUntil,但这是一次性操作 - 一旦控制序列发出,它就不能回到禁用状态 - 所有按钮按下都会被忽略掉控制序列。

如何限制UIButton在某个其他流具有特定值之前不发送tap事件?

let enableButtons = configStatusInputSequence
.filter { (configured, ready) -> Bool in
    return configured && ready
}

for button in controlButtons{
    button.rx.tap
        .skipUntil(enableButtons)
        .bind(to: commandOutputSequence)
        .disposed(by: bag)
}

1
绑定isEnabled属性怎么样?这样按钮就完全无法发出信号了。 - Cristik
@Cristik,您是否建议将“启用按钮”控制流绑定到按钮“Rx.isEnabled”? - Alex Stone
理想情况下,我会保持按钮启用,并将它们的输出引导到另一条路径,例如显示错误消息或打开配置屏幕。 - Alex Stone
您可以这样做,并根据其他可观察对象的状态绑定操作。 - Cristik
1个回答

7
这是我之前写过的一些内容,现在再次呈现。如果您查看我的Gist (https://gist.github.com/danielt1263/1a70c4f7b8960d06bd7f1bfa81802cc3),您会发现我最初将其编写为自定义运算符。后来我了解到下面内置的运算符组合可以完成相同的工作。
回顾Gist中旧版本至少可以让您了解如何编写自己的运算符。
extension ObservableType {

    /**
     Filters the source observable sequence using a trigger observable sequence producing Bool values.
     Elements only go through the filter when the trigger has not completed and its last element was true. If either source or trigger error's, then the source errors.
     - parameter trigger: Triggering event sequence.
     - returns: Filtered observable sequence.
     */
    func filter(if trigger: Observable<Bool>) -> Observable<E> {
        return withLatestFrom(trigger) { (myValue, triggerValue) -> (Element, Bool) in
                return (myValue, triggerValue)
            }
            .filter { (myValue, triggerValue) -> Bool in
                return triggerValue == true
            }
            .map { (myValue, triggerValue) -> Element in
                return myValue
            }
    }
}

如果您想根据控件可观测值的不同更改按钮的功能,请设置两个过滤器。通常,当enableButtons发出true时,过滤器仅通过轻拍。使用地图在第二种情况下将其反转,并将按钮轻按指向另一条路径:

button.rx.tap.filter(if: enableButtons)
    .subscribe(onNext: { /* do one thing when enableButtons emits true */ }
    .disposed(by: bag)

button.rx.tap.filter(if: enableButtons.map { !$0 })
    .subscribe(onNext: { /* do other thing when enable buttons emits false*/ }
    .disposed(by: bag)

我已经查看了withLatestFrom但仍然不明白为什么会有效 :( - Alex Stone
withLatestFrom 的工作方式类似于 combineLatest,但后者在任一可观察对象发出时都会发出元素,而前者仅在主要可观察对象发出元素时才发出。如果您查看代码片段中的先前版本,可以看到其内部运作方式。 - Daniel T.
这是您需要的。我在答案中使用了一个命名元组,以使正在发生的事情更加明显。 - Daniel T.
太好了!我已经编辑了这个例子以澄清 - 我无法阅读所有那些$变量的过滤函数。 - Alex Stone
@AlexStone 如果你要编辑我的代码,至少要做出能够编译的东西。谢谢。 - Daniel T.
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接