如何使用 RxSwift 检测双击

Posted

技术标签:

【中文标题】如何使用 RxSwift 检测双击【英文标题】:How to detect double tap with RxSwift 【发布时间】:2020-02-11 12:32:21 【问题描述】:

我正在尝试使用 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 知道第二个必须失败?

【问题讨论】:

您可以为单击手势设置委托,然后使用shouldRequireFailureOf方法 您是否正在为这些额外的运算符使用库?如果是这样,那是什么?如果不是,那么它们的实现是什么? 设置委托不起作用,在这种情况下你将如何实现shouldRequireFailureOf。您也需要其他手势,对吗? @KishanBhatiya 是的,哦应该加上:RxGesture。 @DanielT。 也许这有帮助:github.com/RxSwiftCommunity/RxGesture/issues/46 【参考方案1】:

我找到了 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

感谢Kishan 建议Jegnux's answer!

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
    

两种解决方案都可以正常工作。

【讨论】:

【参考方案2】:

这段代码应该可以工作:

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 ms)内的连续抽头数。该地图只是为了确保只有12 出来。然后用它做任何你喜欢的条件逻辑。我用UIButton 测试成功。

【讨论】:

所有这些运算符的有趣用法! @Tieme Dank je wel! tap 必须是一个共享的 observable 才能工作

以上是关于如何使用 RxSwift 检测双击的主要内容,如果未能解决你的问题,请参考以下文章

如何检测 QTableView 中的双击

Qt:使用 Modkey(Shift、CTRL 等)检测双击

如何使用 RxSwift 订阅数组更改?

RxSwift,如何更温和地使用 NotificationCenter?

如何使用 Moya RxSwift 合并 REST 数组

如何使用 RxSwift 传递多个参数?