0

I have buttons in the storyboard that I put into a Referencing Outlet Collection. I'm using UITapGestureRecognizer and UILongPressGestureRecognizer for all of these buttons, but how can I print exactly which button gets tapped? Bellow is what I tried but doesn't work. I get an error that says "Value of type 'UILongPressGestureRecognizer' has no member 'tag'." I'm trying to build the button grid for the Minesweeper game. Thank you for your help.

class ViewController: UIViewController { @IBOutlet var testButtons: [UIButton]! // There are 100 buttons in this array

override func viewDidLoad() {
    super.viewDidLoad()

    let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
    testButtonPressed.minimumPressDuration = 0.5
    // These indexes are just to test how to recognize which button gets pressed
    testButtons[0].addGestureRecognizer(testButtonPressed)
    testButtons[1].addGestureRecognizer(testButtonPressed)

}

@objc func testPressed(_ sender: UILongPressGestureRecognizer) {
    print("Test button was pressed")

    print(sender.tag) // THIS DOESN'T WORK, BUT CONCEPTUALLY THIS IS WHAT I WANT TO DO
}
Ryan Kanno
  • 105
  • 8

5 Answers5

0

instead of using gesture I think it would be better to use @IBAction and connect the buttons With it here is a small example

Moumen Alisawe
  • 2,498
  • 2
  • 12
  • 18
  • Ideally I'd like to use IBAction and connect with the buttons, but I haven't found a way to do long pressed gestures with IBAction, which is why I'm currently trying to use the UILongPressGestureRecognizer. Do you know if it's possible to do long pressed gestures with IBAction? – Ryan Kanno Jun 08 '20 at 17:51
0

This error occurs because UILongPressGestureRecognizer object has no tag property

You can access sender's button in a way like that:

@objc func testPressed(_ sender: UILongPressGestureRecognizer) {
    guard let button = sender.view as? UIButton else { return }
    print(button.tag)
}

I think that the best solution to handle button's actions is to add @IBAction (you can add it like @IBOutlet with a minor change - set Action connection type)

And then in @IBAction block you cann access all button properties (like tag and others)

enter image description here

Raman Shyniauski
  • 392
  • 2
  • 13
  • Thank you so much! This was the easiest solution for me to understand, and it works exactly like how I need it to! However, although I would like to use IBAction to access the button properties like tag, is it possible to use IBAction for Long Press Gesture Recognizers? I haven't found a solution for that. – Ryan Kanno Jun 08 '20 at 17:59
  • You can handle not only `TouchUpInside` action in @IBAction. You can also handle `TouchUpOutside` (you can change type method while adding @IBAction) Maybe it will works for you? – Raman Shyniauski Jun 08 '20 at 18:50
0

UILongPressGestureRecognizer which is a subclass of UIGestureRecognizer, can be used only once per button or view. Because UILongPressGestureRecognizer has only a single view property. In your code, it will always be testButtons[1] calling the testPressed action. So you have to first modify the viewDidLoad code like this :-

for button in testButtons {
        let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
        testButtonPressed.minimumPressDuration = 0.5
        button.addGestureRecognizer(testButtonPressed)
        button.addGestureRecognizer(testButtonPressed)
    }

Then you can access the button from testPressed like this (I hope you've already set the tag in the storyboard) :-

@objc func testPressed(_ sender: UILongPressGestureRecognizer) {

    if sender.state == .began {
        if let button = sender.view as? UIButton {
            print(button.tag)
        }
    }
}
Vincent Joy
  • 2,598
  • 15
  • 25
0

You need to set tags before pressing! On the viewDidLoad() method you must add something like:

testButtons.enumerated().forEach {
     let testButtonPressed = UILongPressGestureRecognizer(target: self, action: #selector(testPressed))
     testButtonPressed.minimumPressDuration = 0.5
     $0.element.addGestureRecognizer(testButtonPressed)
     $0.element.tag = $0.offset
}

And when the long press is receiving you need to get a tag from view not from the sender!

print(sender.view?.tag)
Dmytro
  • 131
  • 4
  • Thank you! This worked, but I'm not too familiar with closures and using the $ symbol yet. I will learn from this! – Ryan Kanno Jun 08 '20 at 17:58
0

Since a gesture recognizer should only be associated with a single view, and doesn't directly support using an identity tag to match it with buttons. When creating an array of buttons for a keyboard, with a single gesture response function, I found it easier to use the gesture recognizer "name" property to identify the associated button.

var allNames: [String] = []

// MARK: Long Press Gesture
func addButtonGestureRecognizer(button: UIButton, name: String) {
    let longPrssRcngr = UILongPressGestureRecognizer.init(target: self, action: #selector(longPressOfButton(gestureRecognizer:)))
    longPrssRcngr.minimumPressDuration    = 0.5
    longPrssRcngr.numberOfTouchesRequired = 1
    longPrssRcngr.allowableMovement       = 10.0
    longPrssRcngr.name = name
    allNames.append(name)
    button.addGestureRecognizer(longPrssRcngr)
}

// MARK: Long Key Press
@objc func longPressOfButton(gestureRecognizer: UILongPressGestureRecognizer) {
    print("\nLong Press Button => \(String(describing: gestureRecognizer.name)) : State = \(gestureRecognizer.state)\n")
    if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
        if let keyName = gestureRecognizer.name {
            if allNames.contains(keyName) {
                insertKeyText(key: keyName)
            } else {
                print("No action available for key")
            }
        }
    }
}

To implement, call the addButtonGestureRecognizer function after creating the button, and provide a name for the button (I used the button text) e.g.

addButtonGestureRecognizer(button: keyButton, name: buttonText)

The button name is stored in the "allNames" string array so that it can be matched later in "longPressOfButton".

When the button name is matched in the "longPressOfButton" response function, it passes it to "addKeyFunction" where it is processed.

Golompse
  • 81
  • 2
  • 5