RxSwift: How to add gesture to UILabel?
Solution 1
A UILabel is not configured with a tap gesture recognizer out of the box, that's why RxCocoa does not provide the means to listen to a gesture directly on the label. You will have to add the gesture recognizer yourself. Then you can use Rx to observe events from the recognizer, like so:
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)
Solution 2
Swift 5 (using RxGesture library).
Best and simplest option imho.
label
.rx
.tapGesture()
.when(.recognized) // This is important!
.subscribe(onNext: { [weak self] _ in
guard let self = self else { return }
self.doWhatYouNeedToDo()
})
.disposed(by: disposeBag)
Take care! If you don't use .when(.recognized)
the tap gesture will fire as soon as your label is initialised!
Solution 3
Swift 4 with RxCocoa + RxSwift + RxGesture
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)
or
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)
or event clever, to return an event. i.e string
var buttons: Observable<[UIButton]>!
let stringEvents = buttons
.flatMapLatest({ Observable.merge($0.map({ button in
return button.rx.tapGesture().when(.recognized)
.map({ _ in return "tap" })
}) )
})
Solution 4
You can subscribe label to the tap gesture
label
.rx
.tapGesture()
.subscribe(onNext: { _ in
print("tap")
}).disposed(by: disposeBag)
Solution 5
As Write George Quentin. All work.
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)
Rugmangathan
Updated on April 29, 2021Comments
-
Rugmangathan about 3 years
I have a
label
withisUserInteractionEnabled
set totrue
. Now, I need to addUITapGestureRecognizer
for the label. Is there a way to add inRx
way.I have looked at the RxSwift library here. Which they didn't provide any extension for adding gesture. The
UILabel+Rx
file has onlytext
andattributedText
.Is there any workaround to add gesture to label?
-
Rugmangathan almost 7 yearsFor me, it throws
'UILabel' is not a subtype of 'UIGestureRecognizer'
error. I'm usingIBOutlet
-
RvdB almost 7 yearsI made a mistake in the answer. You need to use
rx.event
on the recognizer instead of the label. I just updated the answer. -
FredFlinstone about 4 yearsThere's no need to create a seperate gesture recogniser. I you use RX in your file you can just do: label.rx.tapGesture()
-
Marcus over 3 yearsIt took me some time to find that this functionality is provided by the RxGesture library.