Reputation: 345
I want to detect number of taps User can tap multiple times and I have to perform action based on number of taps.
I tried using UIButton
with the below code but its detecting all the taps
if I tap three times, It prints
1 2 3
Code -
tapButton.addTarget(self, action: #selector(multipleTap(_:event:)), for: UIControl.Event.touchDownRepeat)
@objc func multipleTap(_ sender: UIButton, event: UIEvent) {
let touch: UITouch = event.allTouches!.first!
print(touch.tapCount)
}
I need the output to be just 3 if i tap three times.
Edit 1: for ex - if you tap three times in youtube it will forward 30 seconds and if you tap 4 times it will forward 40 secs.
Upvotes: 1
Views: 2856
Reputation: 1149
The technique used here is introducing a time delay in executing the final action
static let tapCount = 0
tapButton.addTarget(self, action: #selector(multipleTap(_:event:)), for: UIControl.Event.touchDownRepeat)
// An average user can tap about 7 times in 1 second using 1 finger
DispatchQueue.main.asyncAfter(deadLine: .now() + 1.0 /* We're waiting for a second till executing the target method to observe the total no of taps */ ) {
self.performAction(for: tapCount)
}
@objc func multipleTap(_ sender: UIButton, event: UIEvent) {
tapCount += 1
}
/// Perform the respective action based on the taps
private func performAction(for count: Int) {
// Resetting the taps after 1 second
tapCount = 0
switch (count){
case 2:
// Handle 2 clicks
case 3:
// Handle 3 clicks
case 4:
// Handle 4 clicks
default:
print("Action undefined for count: \(count)")
}
}
Upvotes: 0
Reputation: 131
You need to check time difference for touch events. For ex: If button is pressed 4 times and in particular time, say 1 sec, if it does not get pressed again then you can print 4 taps otherwise don't print.
For this you also need to call the timer so that you can check the time of last event and print accordingly.
var timer : Timer?
var timeDuration = 2.0
var tapCount = 0
var lastButtonPressedTime : Date?
@IBAction func tapCountButtonAction(_ sender: UIButton) {
lastButtonPressedTime = Date()
if(tapCount == 0){
tapCount = 1
timer = Timer.scheduledTimer(withTimeInterval: timeDuration, repeats: true, block: { (timer) in
let difference = Calendar.current.dateComponents([.second], from:self.lastButtonPressedTime!, to:Date())
if(difference.second! > 1){
print(self.tapCount)
timer.invalidate()
self.tapCount = 0
}
})
}else{
tapCount += 1
}
}
Upvotes: 1
Reputation: 11210
I'm not sure for what exactly you need this, but below Duncan's answer I read that you need to copy something from YouTube logic.
Yes, of course you can use tap gesture recognizer, but if you need from some reason UIButton
, you can create its subclass.
After first touch nothing happens, but then after every next touch valueChanged
handler which you will set in view controller gets called. If you don't press button again to certain wait duration, touches
will be reset to 0.
class TouchableButton: UIButton {
var waitDuration: Double = 1.5 // change this for custom duration to reset
var valueChanged: (() -> Void)? // set this to handle press of button
var minimumTouches: Int = 2 // set this to change number of minimum presses
override init(frame: CGRect) {
super.init(frame: frame)
setTarget()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setTarget()
}
private func setTarget() {
addTarget(self, action: #selector(buttonTouched), for: .touchUpInside)
}
@objc private func buttonTouched() {
touches += 1
}
private var timer: Timer?
private var touches: Int = 0 {
didSet {
if touches >= minimumTouches {
valueChanged?()
timer?.invalidate()
timer = Timer.scheduledTimer(withTimeInterval: waitDuration, repeats: false) { _ in
self.touches = 0
}
}
}
}
}
then when you need to set what should happen after every touch, you can set value changed handler
button.valueChanged = { // button of type `TouchableButton`
//print("touched")
... // move 10s forward or backwards
}
you can also change waitDuration
property which specify wait time between last press and time when touches
will be reset
button.waitDuration = 1
also you can set number of minimum touches (first time when valueChanged
gets executed)
button.minimumTouches = 3
Upvotes: 0
Reputation: 101
introduce var to hold tap count
your modified code will be:
tapButton.addTarget(self, action: #selector(singleTap(_:)), for: .touchUpInside)
private var numberOfTaps = 0
private var lastTapDate: Date?
@objc private func singleTap(_ sender: UIButton) {
if let lastTapDate = lastTapDate, Date().timeIntervalSince(lastTapDate) <= 1 { // less then a second
numberOfTaps += 1
} else {
numberOfTaps = 0
}
lastTapDate = Date()
if numberOfTaps == 3 {
// do your rewind stuff here 30 sec
numberOfTaps = 0
}
}
edit: I'm not mind reader, but I guess you look for something like above (updated code)
Upvotes: 1
Reputation: 131501
You aren’t defining the problem clearly. Are you saying that you want to detect a group of repeated taps within a short time as a single, multi-tap event, and report the number of taps? If so, you need to add logic to do that. Decide how long to wait between taps before you consider the event complete.
You’ll then need to keep track of how many taps have occurred, and how long it’s been since the last tap. You’ll need a timer that fires when the inter-tap interval has passed with no new taps so that you can consider the event complete.
All this sounds a lot more like a tap gesture recognizer than a button. Tap gesture recoginizers are written to detect a specific number of taps, with timeouts and such, but don’t respond to variable numbers of taps. You might want to create a custom gesture recognizer that responds to a variable number of taps instead of a button.
Upvotes: 1
Reputation: 706
class ViewController: UIViewController {
var tapCount: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
tapButton.addTarget(self, action: #selector(multipleTap(sender:)), for: .touchUpInside)
}
@objc func multipleTap(sender: UIButton) {
tapCount += 1
if tapCount == 3 {
print(tapCount) //3
}
}
}
Upvotes: 0