Can't Get Simultaneous Gesture Recognition to Work

I'm trying to configure an app that simultaneously allows taps and long presses. For example, if you already have one finger pressing on the screen, you can still tap it with another. The code from this single-view app illustrates the problem. The gestureRecognizer function apparently never gets called by the delegator, but I don't understand why or know how to fix the problem.

Any insights would be helpful. Thanks!


// ViewController.swift

import UIKit

class ViewController: UIViewController, UIGestureRecognizerDelegate {
    @IBOutlet var tapGestureRecognizer: UITapGestureRecognizer!
    @IBOutlet var longPressGestureRecognizer: UILongPressGestureRecognizer!

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
    
        print("This gestureRecognizer function should have gotten called!")
        return true
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    
        let myTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(reportTap(_:)))
        let myLongPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(reportLongPress(_:)))
        myTapGestureRecognizer.delegate = self
        myLongPressGestureRecognizer.delegate = self
    }

    @IBAction func reportTap(_ sender: UITapGestureRecognizer) {
    
        if tapGestureRecognizer.state == .ended { print("Ended tap.") }
    }

    @IBAction func reportLongPress(_ sender: UILongPressGestureRecognizer) {
    
        if longPressGestureRecognizer.state == .began { print("Began press...") }
        else if longPressGestureRecognizer.state == .ended { print("...ended press.") }
    }
}
Answered by Optimalist in 309087022

Thanks, Claude31, for the advice—and for pointing out that my gesture recognizer variables were defined to exist only within viewDidLoad()!


I got the effect I wanted by creating the gesture recognizers programmatically, after first trying and failing to fix my code using the IB-generated gesture recognizers and outlets. Adding the gesture recognizers to the view was the main thing missing from your code, but that was easy to spot. For some reason, though, even the code with the IB-generated recognizers and outlets only allowed simultaneous gestures when I explicitly added the gesture recognizers to the view. Clearly, there's something I don't yet understand about how things get set up behind the scenes. In any case, the link to Ray Wenderlich's site may be helpful, since he show's how to make simultaneous gestures work through IB or code.


In any case, your help got me to a solution (below). Thanks!


// ViewController.swift

import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {

    var tapGestureRecognizer: UITapGestureRecognizer?
    var longPressGestureRecognizer: UILongPressGestureRecognizer?
  
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
  
    func prepareForGestures() {
      
        tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(reportTap(_:)))
        longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(reportLongPress(_:)))
        tapGestureRecognizer?.delegate = self
        longPressGestureRecognizer?.delegate = self
      
        if let tapGestureRecognizer = tapGestureRecognizer {
            view.addGestureRecognizer(tapGestureRecognizer)
        }
      
        if let longPressGestureRecognizer = longPressGestureRecognizer {
            view.addGestureRecognizer(longPressGestureRecognizer)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        prepareForGestures()
    }
  
    @IBAction func reportTap(_ sender: UITapGestureRecognizer) {
      
        if tapGestureRecognizer?.state == .ended { print("Ended tap.") }
    }
  
    @IBAction func reportLongPress(_ sender: UILongPressGestureRecognizer) {
      
        if longPressGestureRecognizer?.state == .began { print("Began press...") }
        else if longPressGestureRecognizer?.state == .ended { print("...ended press.") }
    }
}

You define myTapGestureRecognizer as a new constant in viewDidload: it disappears when exiting.


Why not use tapGestureRecognizer, but then why do you need an outlet ? Either you create in storyboard or you create programmatically.

this may be interesting to read:

h ttps://www.raywenderlich.com/162745/uigesturerecognizer-tutorial-getting-started


So, I would write (but I did not test):

class ViewController: UIViewController, UIGestureRecognizerDelegate {
    var tapGestureRecognizer: UITapGestureRecognizer?
    var longPressGestureRecognizer: UILongPressGestureRecognizer?

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
  
        print("This gestureRecognizer function should have gotten called!")
        return true
    }

    override func viewDidLoad() {
        super.viewDidLoad()
  
       tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(reportTap(_:)))
       longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(reportLongPress(_:)))
       tapGestureRecognizer.delegate = self
       longPressGestureRecognizer.delegate = self
    }


Maybe this could be of some help?:

h ttps://stackoverflow.com/questions/34548263/button-tap-and-long-press-gesture

Accepted Answer

Thanks, Claude31, for the advice—and for pointing out that my gesture recognizer variables were defined to exist only within viewDidLoad()!


I got the effect I wanted by creating the gesture recognizers programmatically, after first trying and failing to fix my code using the IB-generated gesture recognizers and outlets. Adding the gesture recognizers to the view was the main thing missing from your code, but that was easy to spot. For some reason, though, even the code with the IB-generated recognizers and outlets only allowed simultaneous gestures when I explicitly added the gesture recognizers to the view. Clearly, there's something I don't yet understand about how things get set up behind the scenes. In any case, the link to Ray Wenderlich's site may be helpful, since he show's how to make simultaneous gestures work through IB or code.


In any case, your help got me to a solution (below). Thanks!


// ViewController.swift

import UIKit
class ViewController: UIViewController, UIGestureRecognizerDelegate {

    var tapGestureRecognizer: UITapGestureRecognizer?
    var longPressGestureRecognizer: UILongPressGestureRecognizer?
  
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
  
    func prepareForGestures() {
      
        tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(reportTap(_:)))
        longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(reportLongPress(_:)))
        tapGestureRecognizer?.delegate = self
        longPressGestureRecognizer?.delegate = self
      
        if let tapGestureRecognizer = tapGestureRecognizer {
            view.addGestureRecognizer(tapGestureRecognizer)
        }
      
        if let longPressGestureRecognizer = longPressGestureRecognizer {
            view.addGestureRecognizer(longPressGestureRecognizer)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        prepareForGestures()
    }
  
    @IBAction func reportTap(_ sender: UITapGestureRecognizer) {
      
        if tapGestureRecognizer?.state == .ended { print("Ended tap.") }
    }
  
    @IBAction func reportLongPress(_ sender: UILongPressGestureRecognizer) {
      
        if longPressGestureRecognizer?.state == .began { print("Began press...") }
        else if longPressGestureRecognizer?.state == .ended { print("...ended press.") }
    }
}
Can't Get Simultaneous Gesture Recognition to Work
 
 
Q