Abhinav Jha
Abhinav Jha

Reputation: 345

How to detect number of taps

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

Answers (6)

Daniel Selvan
Daniel Selvan

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

Mahak Mittal
Mahak Mittal

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

Robert Dresler
Robert Dresler

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

Mykola Savula
Mykola Savula

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

Duncan C
Duncan C

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

Abhishek Jadhav
Abhishek Jadhav

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

Related Questions