3

我正在尝试检测 observable(我的 case button.rx.tap)是否在 3 秒内没有发出任何值。如果是,我想更新用户界面。到目前为止,这是我的尝试:

Observable<Int>.interval(3, scheduler: MainScheduler.instance)
    .takeUntil(button.rx.tap) // I know take until will stop the timer sequence 
    .subscribe({ event in
        print(event)
        UIView.animate(withDuration: 0.4, animations: {
            if let number = event.element {
                let scale: CGFloat = number % 2 == 0 ? 1.5 : 1.0
                self.button.transform = CGAffineTransform(scaleX: scale, y: scale)
            }
        })
    })
    .addDisposableTo(disposeBag)

我的目标是在三秒钟内未点击按钮时为视图设置动画。我已经尝试过scandistinctUntilChangeddebounce,但我遇到的大多数组合运算符只会在可观察项发出项目时才会发出项目。任何帮助深表感谢。

4

1 回答 1

9
enum Event {
case tap
case timeout
}

let tapOrTimeout = button.rx.tap
  .map { _ in Event.tap }
  .timeout(3, scheduler: MainScheduler.instance)
  .catchErrorJustReturn(.timeout)

Observable.repeatElement(tapOrTimeout).concat()
  .subscribe(onNext: { event in
    switch event {
    case .tap: tapHandler()
    case .timeout: callForAttention()
    }
  })
  • timeout(_:scheduler:)如果在 3 秒内没有事件从链中出来,将引发错误。
  • catchErrorJustReturn(_:)将错误转换为.timeout事件
  • 此时,如果 observable 超时,它也将完成,因此之后不会发生任何事情。使用Observable.repeatElement(_:).concat()我们首先创建一个Observable<Observable<Event>>然后连接内部可观察对象。在我们的例子中,这意味着我们将订阅第一个,如果第一个完成,则重新订阅相同的 observable。

如果我们宁愿只播放callForAttention()一次动画,我们可以做以下

let tap = button.rx.tap
  .map { _ in Event.tap }

let tapOrTimeout = tap  
  .timeout(3, scheduler: MainScheduler.instance)
  .catchErrorJustReturn(.timeout)

Observable.of(tapOrTimeout, tap).concat()
  .subscribe(onNext: { /* same as above */})

这样,我们首先超时,然后仅在点击发生时才发出事件。

于 2017-02-10T04:27:40.770 回答