RxSwift:如何为UILabel添加手势?

36

我有一个labelisUserInteractionEnabled设置为true。现在,我需要为标签添加UITapGestureRecognizer。有没有一种使用Rx的方法来实现。

我查看了RxSwift库 这里。他们没有提供添加手势的扩展。UILabel+Rx文件仅包含textattributedText

是否有任何解决办法来为标签添加手势?

7个回答

77

UILabel默认不包含点击手势识别器,这就是为什么RxCocoa没有直接提供监听标签上手势的方法。你需要自己添加手势识别器。然后,你就可以使用Rx来观察手势识别器的事件,像这样:

let disposeBag = DisposeBag()
let label = UILabel()
label.text = "Hello World!"

let tapGesture = UITapGestureRecognizer()
label.addGestureRecognizer(tapGesture)

tapGesture.rx.event.bind(onNext: { recognizer in
    print("touches: \(recognizer.numberOfTouches)") //or whatever you like
}).disposed(by: disposeBag)

对我来说,它抛出了“'UILabel'不是'UIGestureRecognizer'的子类型”的错误。我正在使用IBOutlet。 - Rugmangathan
1
我在答案中犯了一个错误。你需要在识别器上使用 rx.event 而不是标签。我刚刚更新了答案。 - RvdB
1
不需要创建单独的手势识别器。如果您在文件中使用RX,只需执行:label.rx.tapGesture()。 - FredFlinstone

21

使用RxGesture库的Swift 5。

在我看来,这是最好、最简单的选择。

     label
        .rx
        .tapGesture()
        .when(.recognized) // This is important!
        .subscribe(onNext: { [weak self] _ in
            guard let self = self else { return }
            self.doWhatYouNeedToDo()
        })
        .disposed(by: disposeBag)

注意! 如果您不使用 .when(.recognized),则轻拍手势将在标签初始化时立即触发!


6
我找了一段时间才发现这个功能是由RxGesture库提供的。 - Marcus

12

使用 RxCocoa + RxSwift + RxGesture 的 Swift 4

let disposeBag = DisposeBag()
let myView = UIView()

myView.rx
  .longPressGesture(numberOfTouchesRequired: 1,
                    numberOfTapsRequired: 0,
                    minimumPressDuration: 0.01,
                    allowableMovement: 1.0)
            .when(.began, .changed, .ended)
            .subscribe(onNext: { pan in
                let view = pan.view
                let location = pan.location(in: view)
                switch pan.state {
                case .began:
                    print("began")
                case .changed:
                    print("changed \(location)")
                case .ended:
                    print("ended")
                default:
                    break
                }
            }).disposed(by bag)

或者

myView.rx
.gesture(.tap(), .pan(), .swipe([.up, .down]))
.subscribe({ onNext: gesture in
    switch gesture {
    case .tap: // Do something
    case .pan: // Do something
    case .swipeUp: // Do something 
    default: break       
    }        
}).disposed(by: bag)

者聪明,才能返回一个事件。例如字符串。

var buttons: Observable<[UIButton]>!

let stringEvents = buttons
        .flatMapLatest({ Observable.merge($0.map({ button in
            return button.rx.tapGesture().when(.recognized)
                .map({ _ in return "tap" })
            }) )
        })

2

作为George Quentin的写作,所有工作。

    view.rx
        .longPressGesture(configuration: { gestureRecognizer, delegate in
            gestureRecognizer.numberOfTouchesRequired = 1
            gestureRecognizer.numberOfTapsRequired = 0
            gestureRecognizer.minimumPressDuration = 0.01
            gestureRecognizer.allowableMovement = 1.0
        })
        .when(.began, .changed, .ended)
        .subscribe(onNext: { pan in
            let view = pan.view
            let location = pan.location(in: view)
            switch pan.state {
            case .began:
                print(":DEBUG:began")
            case .changed:
                print(":DEBUG:changed \(location)")
            case .ended:
                print(":DEBUG:end \(location)")
                nextStep()
            default:
                break
            }
        })
        .disposed(by: stepBag)

1
那些扩展技术上属于 RxCocoa 库,该库目前已打包在 RxSwift 中。
您应该能够将 UITapGestureRecognizer 添加到视图中,然后只需在该手势对象上使用 rx.event(如果是旧版本,则为 rx_event)即可。
如果您必须在 UILabel 的上下文中执行此操作,则可能需要将其包装在 UILabel+Rx 中,但如果您有更简单的要求,只需在手势上使用 rx.event 应该是一个不错的解决方法。

1
你可以将标签订阅到触摸手势上。
    label
        .rx
        .tapGesture()
        .subscribe(onNext: { _ in
            print("tap")
        }).disposed(by: disposeBag)

0

我在UI层简单地使用这个扩展来获取Driver

public extension Reactive where Base: RxGestureView {
    func justTap() -> Driver<Void> {
        return tapGesture()
            .when(.recognized)
            .map{ _ in }
            .asDriver { _ in
                return Driver.empty()
            }
    }
}

当我需要触发点击事件时,我调用这个函数

view.rx.justTap()

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