1

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.

Abhinav Jha
  • 295
  • 1
  • 17
  • What output do you want after 3 taps? – Abhishek Jadhav Jan 16 '19 at 11:30
  • I need the output to be just 3 if i tap three times. its printing 1 2 3 now – Abhinav Jha Jan 16 '19 at 11:30
  • you write print statement, so it print how many taps you are going to tap on button if you want particular tap then write a condition touch.tapCount == 3 then print 3 – Abhishek Jadhav Jan 16 '19 at 11:32
  • @AbhishekJadhav if i will tap four times it will pass the condition for three aswell, I tried this already – Abhinav Jha Jan 16 '19 at 11:37
  • Yes @Kuldeep thats my requirement – Abhinav Jha Jan 16 '19 at 11:39
  • No, if tap count is 4 then 4 == 3 this condtion is getting false how it will excute? – Abhishek Jadhav Jan 16 '19 at 11:40
  • Your edit doesn't help. In the Youtube app it might just advance the playback by 10 seconds for each tap, and not worry about whether the user did a single, double, or triple-tap. You need to state explicitly what you want to do. It sounds to me like you want to collect taps until the user stops tapping, and then trigger code with the total number of taps. Is that correct? You need to be clear on your requirements, both in your question, and in your problem-solving. – Duncan C Jan 16 '19 at 13:18
  • As per understanding you want to fast forward any video with interval of 10 seconds in tap like if user press 3 times so it will be forward 30 seconds Right ? –  Jan 16 '19 at 13:21

6 Answers6

1

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)

Mykola Savula
  • 91
  • 1
  • 5
1

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.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • I have added an edit in my question - 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. – Abhinav Jha Jan 16 '19 at 11:55
0

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
    }
}
Mahak Mittal
  • 121
  • 1
  • 10
  • Would you please provide some more details – Abhinav Jha Jan 16 '19 at 11:43
  • Sure. You need to define a timer, which you can call every second. In the button action you need to record current time in global variable and no of counts as well. in the timer function you can check time difference between current time and the time in the global variable. – Mahak Mittal Jan 16 '19 at 11:51
  • if the time difference is more then 1 sec then you can print number of taps. – Mahak Mittal Jan 16 '19 at 11:51
0
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
         }
    }
}
Abhishek Jadhav
  • 706
  • 5
  • 12
0

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)")
    }
}
piet.t
  • 11,718
  • 21
  • 43
  • 52
Daniel Selvan
  • 959
  • 10
  • 23
0

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
Robert Dresler
  • 10,580
  • 2
  • 22
  • 40