Как обнаружить двойной тап с помощью RxSwift - PullRequest
0 голосов
/ 11 февраля 2020

Я пытаюсь обнаружить двойное нажатие с помощью RxSwift

Без RxSwift Я хотел бы что-то вроде этого:

private func setupFakePanView() {
    let singleTapGesture = UITapGestureRecognizer()
    let doubleTapGesture = UITapGestureRecognizer()

    singleTapGesture.numberOfTapsRequired = 1
    doubleTapGesture.numberOfTapsRequired = 2

    singleTapGesture.addTarget(self, action: #selector(self.tapped))
    doubleTapGesture.addTarget(self, action: #selector(self.doubleTapped))

    someView.addGestureRecognizer(singleTapGesture)
    someView.addGestureRecognizer(doubleTapGesture)

    singleTapGesture.require(toFail: doubleTapGesture)
}

@objc private func tapped() {
    // Do something
}

@objc private func doubleTapped() {
    // Do something else
}

Есть ли способ, которым я мог бы добиться того же с RxSwift, RxCocoa и RxGesture ? Я пробовал следующее, но, конечно, это не работает:

someView.rx
    .tapGesture(numberOfTouchesRequired: 1, numberOfTapsRequired: 1)
    .when(.recognized)
    .subscribe(onNext: { _ in
        // Do something
    })
    .disposed(by: bag)

someView.rx
    .tapGesture(numberOfTouchesRequired: 1, numberOfTapsRequired: 2)
    .when(.recognized)
    .subscribe(onNext: { _ in
        // Do something else
    })
    .disposed(by: bag)

Есть ли способ сообщить первому значению tapGesture, что второй должен дать сбой?

Ответы [ 2 ]

2 голосов
/ 11 февраля 2020

Я нашел 2 решения для решения этой проблемы!

A. Использование пользовательского UITapGestureRecognizer

let doubleTapGesture = UITapGestureRecognizer()
doubleTapGesture.numberOfTapsRequired = 2

let singleTapGesture = UITapGestureRecognizer()
singleTapGesture.numberOfTapsRequired = 1
singleTapGesture.require(toFail: doubleTapGesture)

let singleTap = someView.rx
    .gesture(singleTapGesture)
    .when(.recognized)
    .subscribe(onNext: { _ in
        // Do something
    })
    .disposed(by: bag)


let doubleTap = someView.rx
    .gesture(doubleTapGesture)
    .when(.recognized)
    .subscribe(onNext: { _ in
        // Do something else
    })
    .disposed(by: bag)

или ..

B. Использование пользовательского UIGestureRecognizerDelegate

Спасибо Кишан за предложение Ответ Джегнукса !

1 - Установить пользовательский делегат для одного жеста касания. .

someView.rx
    .tapGesture(
        numberOfTouchesRequired: 1,
        numberOfTapsRequired: 1,
        configuration: { [weak self] gesture, delegate in
            gesture.delegate = self
        }
    )
    .subscribe(onNext: { _ in
        // Do something
    })
    .disposed(by: bag)

// double tap same as before

2 - Реализация gestureRecognizer(_:shouldRequireFailureOf:)

extension MyController: UIGestureRecognizerDelegate {
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        if let gesture = otherGestureRecognizer as? UITapGestureRecognizer, gesture.numberOfTapsRequired == 2 {
             return true
        }
        return false
    }
}

Оба решения работают нормально.

1 голос
/ 12 февраля 2020

Этот код должен работать:

tap
    .flatMapFirst {
        tap
        .takeUntil(tap.startWith(()).debounce(.milliseconds(300), scheduler: MainScheduler.instance))
        .startWith(())
        .reduce(0) { acc, _ in acc + 1 }
    }
    .map { min($0, 2) }

Просто используйте один распознаватель жестов (чье событие называется tap), который генерируется мгновенно, когда происходит касание. Код выше map обобщает эту проблему для вывода количества последовательных отводов в течение определенного периода друг от друга (300 мс) в этом случае. Карта просто гарантирует, что выйдет только 1 или 2. Затем делайте с ней все условные логи c, какие пожелаете. Я успешно проверил его с UIButton.

...