LoginSignup
9
7

More than 5 years have passed since last update.

RxSwift 3.3 でダブルタップを正確に検知

Posted at

やりたいこと

RxSwiftで「x秒間なにもイベントがなかったらそれまでの値をまとめて受け取りたい」という状況はよくあると思います。

例えばダブルタップだと「0.25秒間なにもイベントがなかったとき、それまでのタップ数が2回だったらダブルタップである」という判定ができます。

他言語では

RxJSなどではこのような要件は bufferdebounce (throttle) を組み合わせると簡単に実現できます。

buffer の引数にどのタイミングでイベントをまとめるかの条件を渡せるので、debounce を使って「x秒間なにもなかったら」という条件を指定できます 1

clickStream.buffer(clickStream.debounce(250))

RxSwiftでは

現在 buffer が条件を受け取れる作りになっていません。
なので自前でなにかしら以下のようなものを作ってやる必要があります 2

extension ObservableType {
    func debouncedBuffer(_ dueTime: RxTimeInterval, scheduler: SchedulerType) -> Observable<[E]> {
        var buffer: [E] = []
        return self.do(onNext: { value in
            buffer.append(value)
        }).debounce(dueTime, scheduler: scheduler).flatMap { value -> Observable<[E]> in
            defer { buffer.removeAll() }
            return Observable<[E]>.just(buffer)
        }
    }
}

そうするとこのように書けます。

        button.rx.tap
            .debouncedBuffer(0.25, scheduler: MainScheduler.instance)
            .filter { $0.count == 2 }
            .subscribe(onNext: { _ in
                print("double tap")
            })
            .disposed(by: disposeBag)

参考


  1. 【翻訳】あなたが求めていたリアクティブプログラミング入門 - ninjinkun's diary 

  2. swift - Implementing a debounced buffer with RxSwift, is this correct? - Stack Overflow
    コードはこのStackOverflowのページを参考にしました :bow:
    bufferObservable を渡せるようなサンプルコードも載っているので興味ある方は見てみてください。 

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7