3

I set one UILongPressGestureRecognizer to handle four different buttons in my view, how do I access which button is being clicked in my code?

My UILongPressGestureRecognizer looks like it:

@IBAction func editText(sender: UILongPressGestureRecognizer) {
        textFieldInput.hidden = false
        iphoneSaveCharName.hidden = false
      }

And I Want to use Long Press so that I can edit the button text

EDIT 1:

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var iphoneTableView: UITableView!
    @IBOutlet weak var textFieldInput: UITextField!
    @IBOutlet weak var iphoneSaveCharName: UIButton!
    @IBOutlet weak var charOne: UILabel!
    @IBOutlet weak var charTwo: UILabel!
    @IBOutlet weak var charTree: UILabel!
    @IBOutlet weak var charFour: UILabel!
    @IBOutlet weak var test1: UIButton! //button that I am clicking on!



    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //Function I made so I can save the user input
    @IBAction func iphoneSaveTextInput(sender: UIButton) {
        let textData = textFieldInput.text
        textFieldInput.hidden = true
        iphoneSaveCharName.hidden = true
        charTwo.text = textData

    }

    // This is the LongPress Action
    @IBAction func editText(sender: UILongPressGestureRecognizer) {
        textFieldInput.hidden = false
        iphoneSaveCharName.hidden = false

        func longPressMethod(gesture: UILongPressGestureRecognizer) {

            println(gesture.view)

            if gesture.view is UIButton {

                let test1 = gesture.view as UIButton
                println(test1)
            }
        }

    }
}

Edit 2: Layout

Edit 3: New ViewController

 import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var iphoneTableView: UITableView!
    @IBOutlet weak var textFieldInput: UITextField!
    @IBOutlet weak var iphoneSaveCharName: UIButton!
    @IBOutlet weak var charOne: UIButton!
    @IBOutlet weak var charTwo: UIButton!
    @IBOutlet weak var charThree: UIButton!
    @IBOutlet weak var charFour: UIButton!




    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func iphoneSaveTextInput(sender: UIButton) -> Void{

        let textData = textFieldInput.text
        textFieldInput.hidden = true
        iphoneSaveCharName.hidden = true
    }

    @IBAction func editText(sender: AnyObject) {
        if sender is UILongPressGestureRecognizer &&
            sender.state == UIGestureRecognizerState.Began {

                textFieldInput.hidden = false
                iphoneSaveCharName.hidden = false

//                func iphoneSaveTextInput(sender: UIButton){
//                    var textData = textFieldInput.text
//                    textFieldInput.hidden = true
//                    iphoneSaveCharName.hidden = true
//                
//                }

                let button = sender.view as UIButton
                println(button)

                if button.tag == 1{
                    charOne.setTitle("textData", forState: .Normal)
                } else if button.tag == 2{
                    charTwo.setTitle("textData2", forState: .Normal)
                } else if button.tag == 3{
                    charThree.setTitle("textData3", forState: .Normal)
                } else if button.tag == 4{
                    charFour.setTitle("textData4", forState: .Normal)
                }
        }
    }
}

Answer:

This is the final view control:

import UIKit

class ViewController: UIViewController {
    @IBOutlet weak var iphoneTableView: UITableView!
    @IBOutlet weak var textFieldInput: UITextField!
    @IBOutlet weak var iphoneSaveCharName: UIButton!
    @IBOutlet weak var charOne: UIButton!
    @IBOutlet weak var charTwo: UIButton!
    @IBOutlet weak var charThree: UIButton!
    @IBOutlet weak var charFour: UIButton!




    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    @IBAction func iphoneSaveTextInput(sender: UIButton) -> Void{

        let textData = textFieldInput.text
        textFieldInput.hidden = true
        iphoneSaveCharName.hidden = true
    }


    @IBAction func editText(sender: AnyObject) {
        if sender is UILongPressGestureRecognizer &&
            sender.state == UIGestureRecognizerState.Began {

                textFieldInput.hidden = false
                iphoneSaveCharName.hidden = false

//                func iphoneSaveTextInput(sender: UIButton){
//                    var textData = textFieldInput.text
//                    textFieldInput.hidden = true
//                    iphoneSaveCharName.hidden = true
//                
//                }

                let button = sender.view as UIButton
                println(button)

                if button.tag == 1{
                    charOne.setTitle("textData", forState: .Normal)
                } else if button.tag == 2{
                    charTwo.setTitle("textData2", forState: .Normal)
                } else if button.tag == 3{
                    charThree.setTitle("textData3", forState: .Normal)
                } else if button.tag == 4{
                    charFour.setTitle("textData4", forState: .Normal)
                }
        }
    }
}

I would mostly like to give you all a best answer since everybody helped me out! I had to create one Long Press for each button, otherwise code will get confused.

Skalwalker
  • 299
  • 3
  • 23
  • 1
    How did you set that gesture recognizer ? – Midhun MP Dec 17 '14 at 23:36
  • 1
    Why did you need `UILongPressGestureRecognizer` for buttons ? – Midhun MP Dec 17 '14 at 23:38
  • It's not at all clear why you're adding a long press gesture recognizer to buttons. You don't need that to edit the button text. You should explain what you're trying to accomplish, so we can offer a better solution. – rdelmar Dec 18 '14 at 00:51
  • re: Edit 1. That's not what I meant... I didn't mean to put the func within another... But if you do put a function within another, you actually have to call that inner function in order for it to execute... I'll update my answer to comply with your current code. – Lyndsey Scott Dec 18 '14 at 00:54
  • The User should be able to edit the label at the button. The button will have to functions, one if you hold click you will edit the label but if you just click will open another View – Skalwalker Dec 18 '14 at 00:56
  • Sorry for being confusing is my first project. – Skalwalker Dec 18 '14 at 00:58
  • @Skal It's still confusing to be honest... Why/how are you using an IBAction for the long press gesture recognizer? – Lyndsey Scott Dec 18 '14 at 01:00
  • You can do that by having one method on touchDown which starts a timer that is cancelled on touchUp. If the timer is not cancelled within a set time, you edit the label, if it is, you open the other view. No need for a gesture recognizer. – rdelmar Dec 18 '14 at 01:00
  • @Skal Actually I'm testing it now and there might be a way to make it work as an IBAction... Looking into it... Actually what I'm seeing is very interesting... And you may not be so far off after all! – Lyndsey Scott Dec 18 '14 at 01:03
  • I posted a image of my layout as you guys can see there is four buttons(a border image, couldn't set with text), and four labels for each button. Under the label there is some hide layout that is to take the user input when he wants to edit the name(I tried to do just by hitting the return key on the keyboard, but couldn't do it either). So when the user uses the long press it will make it visible and it will be able to edit it and save to the button you clicked on. – Skalwalker Dec 18 '14 at 01:11
  • What doe mean by 4 labels for each button? Do you have UILabels there, or are you talking about the button's titleLabel? Is the view that says "Character 1" a button? – rdelmar Dec 18 '14 at 01:30
  • @rdelmar But yeah, if the OP's talking about labels and not buttons then so much for that... – Lyndsey Scott Dec 18 '14 at 01:33
  • @rdelmar it is a label, but that doesn't matter,the button is the blue label that I did on photoshop, and we are clicking on that, so it won't make a different, I want to know the button that is being clicked on. – Skalwalker Dec 18 '14 at 01:43
  • I don't understand you last comment. You have a rounded rect with a blue outline with some blue text in it. Is that a button with a label on top of it?? I don't see why you're using a label at all, since a button has its own titleLabel. – rdelmar Dec 18 '14 at 01:52
  • And to add to @rdelmar's comment do you actually have 4 buttons or just 4 labels? – Lyndsey Scott Dec 18 '14 at 02:22
  • I have 4 buttons and 4 labels, I have a label on top of the button indeed, because I couldn't set the text to be on the center of the image. – Skalwalker Dec 18 '14 at 02:24
  • Hey, just figured out, I am taking the labels off right now! – Skalwalker Dec 18 '14 at 02:32

3 Answers3

5

Your question has introduced me to a really cool feature, so thanks! :)

It turns out that if you attach a UILongPressGestureRecognizer to a UIButton in a storyboard and attach that button and gesture to an IBAction within your swift class, that IBAction method can recognize whether the touch is a tap or long press! Pretty cool, huh?

So first off, make sure that each UIButton has its own unique UILongPressGestureRecognizer; then you can edit your code like so, so that it's able to identify which button is being pressed and whether that press is either a simple tap or UILongPressGestureRecognizer:

// Connect both your button *and* its gestures to the
// `IBAction` method so that the function will be called
// no matter what kind of gesture it recognizes -- tap, 
// long press, or otherwise.
@IBAction func buttonSelected(sender: AnyObject) {

    // But to see if the gesture is a long press, you can
    // simply check the sender's class and execute the code
    // when the gesture begins.
    if sender is UILongPressGestureRecognizer &&
        sender.state == UIGestureRecognizerState.Began {

        // These two lines are originally from your
        // editText method
        textFieldInput.hidden = false
        iphoneSaveCharName.hidden = false

        // Then to identify which button was long pressed you
        // can check the sender's view, to see which button IBOutlet
        // that gesture's view belongs to.

        // Method #1:

        let button = sender.view as UIButton

        if button == thisButton {

        } else if button == thatButton {

        }
        ...

        // Or you can check the gesture view's tag to see which
        // button it belongs to (i.e. whichever button has a matching
        // tag).

        // Method #2:

        let button = sender.view as UIButton

        if button.tag == 1 {

        } else if button.tag == 2 {

        }
        ...
    }

    // Else if it's not a long press gesture, perform
    // whatever action you'd like to accomplish during a
    // normal button tap
    else if !(sender is UILongPressGestureRecognizer) {

        // These lines are originally from your
        // iphoneSaveTextInput
        let textData = textFieldInput.text
        textFieldInput.hidden = true
        iphoneSaveCharName.hidden = true

    }
}

But if you want to continue to keep the UILongPressGestureRecognizer IBAction separate from the UIButton's IBAction (i.e. link the UIButtons to iphoneSaveTextInput: and your UILongPressGestureRecognizers to editText:), that should be OK too. Just keep your iphoneSaveTextInput: method as is, and update your editText: method like so:

// This is the LongPress Action
@IBAction func editText(sender: UILongPressGestureRecognizer) {

    if sender.state == UIGestureRecognizerState.Began {

        textFieldInput.hidden = false
        iphoneSaveCharName.hidden = false

        // Then to identify which button was long pressed you
        // can check the sender's view, to see which button IBOutlet
        // that gesture's view belongs to.

        // Method #1:

        let button = sender.view as UIButton

        if button == thisButton {

        } else if button == thatButton {

        }
        ...

        // Or you can check the gesture view's tag to see which
        // button it belongs to (i.e. whichever button has a matching
        // tag).

        // Method #2:

        let button = sender.view as UIButton

        if button.tag == 1 {

        } else if button.tag == 2 {

        }
        ...

    }
}
Lyndsey Scott
  • 37,080
  • 10
  • 92
  • 128
  • I can't get the code you gave me to be executed, I posted my ViewController for you to take a look – Skalwalker Dec 18 '14 at 00:48
  • @Skal What are you saying? "here it is my control view:" – Lyndsey Scott Dec 18 '14 at 00:49
  • Sorry I hit return thinking it would skip a line and accidentally posted it. – Skalwalker Dec 18 '14 at 00:53
  • @Skal No worries. I'm going to update my answer using your current code anyway. – Lyndsey Scott Dec 18 '14 at 01:08
  • Hi, you that are helping me out here but anyway, you are welcome hahahaha! But still one thing, in the "let sender = gesture.view as UIButton" is pointing that gesture is a unresolved identifier, should I substitute it for something? – Skalwalker Dec 18 '14 at 01:37
  • @Skal Oh whoops I realize what you're saying... I messed up my variables. – Lyndsey Scott Dec 18 '14 at 01:40
  • look like it is working, but I need my "@IBAction func iphoneSaveTextInput" inside the "func buttonSelected" under the if ... is.. statement, how should I do that? – Skalwalker Dec 18 '14 at 02:26
  • @Skal I don't understand... You mean you want to perform the actions in iphoneSaveTextInput when the button's tapped? – Lyndsey Scott Dec 18 '14 at 02:44
  • Yup! Except the last line, I erased that. I need to access the textData constant that I created so I can use it as a title for the button. – Skalwalker Dec 18 '14 at 02:45
  • OK, I see what you were originally trying to do... But to use my first block of code you have to link both the button and the gesture to the same method, i.e. buttonSelected in this case. I've inserted your code in the appropriate places. Technically though, you could continue to split the methods up by linking the button to iphoneSaveTextInput and the long press to editText... I've updated my code to include that scenario as well. – Lyndsey Scott Dec 18 '14 at 03:24
  • I had already done the part you posted, getting the textData value is really my problem. Oh and looks like your code isn't work, the .view is the same for all the buttons: ; layer = > – Skalwalker Dec 18 '14 at 03:44
  • @Skal I've tested this code and it works for me. The view is not the same for all the buttons as long as you've connected everything correctly. I think you've mixed up your outlets. As for textData, I have no way of knowing what that even is because you haven't mentioned what it is in your question. – Lyndsey Scott Dec 18 '14 at 04:15
  • textData is the variable inside iphoneSaveTextInput function that I need to call on the editText. – Skalwalker Dec 18 '14 at 04:28
  • Hey Lyndesy, it is finally over I solved the problem!But as @bjtitus said it indeed need multiple long press gesture recognizer otherwise will get confused. – Skalwalker Dec 18 '14 at 15:20
  • @Skal Glad to hear :) I tested my code and this solution worked for me, but you should accept bjtitus's answer instead if it worked for you. – Lyndsey Scott Dec 18 '14 at 15:22
  • But your answer is right too, check out my update on the question so you can see my final ViewControll – Skalwalker Dec 18 '14 at 15:26
  • @Skal Oh I see! Yes, I meant that too...that every button should have a unique long press gesture recognizer. That must be why all your views were the same. I should update my answer to clarify that. Glad you figured it out. :) – Lyndsey Scott Dec 18 '14 at 15:29
  • Oh I didn't see that. Sometimes I get lost with english – Skalwalker Dec 18 '14 at 15:32
0

You don't want to use the same gesture recognizer across different views:

Can you attach a UIGestureRecognizer to multiple views?

The view property of the gesture recognizer is probably what you would want to check but you want different gesture recognizers for each view.

If you want, they could all be linked to the same selector, though, and you could access the incoming recognizer's view that way.

Community
  • 1
  • 1
bjtitus
  • 4,231
  • 1
  • 27
  • 35
0

A general way to make a button have different actions based on how long you press it, looks like this (timer is a property),

@IBAction func buttonDown(sender: UIButton) { // connected to touchDown
       timer = NSTimer.scheduledTimerWithTimeInterval(0.5, target: self, selector: "handleTimer", userInfo: sender, repeats: false)
    }


    @IBAction func buttonUp(sender: UIButton) { // connected to touchUpInside
        if timer != nil {
            timer.invalidate()
            println("change view")
        }
    }


    func handleTimer() {
        var button = timer.userInfo as UIButton
        timer = nil
        button.setTitle("New Title", forState: .Normal)
    }
rdelmar
  • 103,982
  • 12
  • 207
  • 218
  • Great answer. But check out mine to learn about a really cool Swift specific feature I just found out about through testing! (Obviously I'm waaay too excited by this "discovery".) – Lyndsey Scott Dec 18 '14 at 01:31
  • 1
    @LyndseyScott, hate to burst you bubble, but there's nothing Swift specific about that -- you get the same result in Objective-C if you connect a button and a long press recognizer to the same method. Nevertheless, it is an interesting way to override a button's normal action method. – rdelmar Dec 18 '14 at 01:48
  • Oh, I tried it in Obj-C and it didn't work for me for some reason... But still pretty cool. – Lyndsey Scott Dec 18 '14 at 01:49
  • Anyway, I get the feeling that my "discovery" was the OP's original intent in using an IBAction with a UILongPressGestureRecognizer parameter. – Lyndsey Scott Dec 18 '14 at 02:20