How do I toggle hidden of a label while a button is pressed?

2.8k views Asked by At

I am trying to figure out how to only display a label while a button is pressed in OS. I know how to operate the touch events but I am not sure how to incorporate the UILongPressGestureRecognizer into this.

2

There are 2 answers

2
nhgrif On BEST ANSWER

The UIButton class, as well as lots of other UIControl subclasses can have numerous actions hooked up to them.

When we are hooking up an action from interface builder to our source code file, if we open the "Event" drop down, we're presented with a long list of options:

Choosing IBAction event

In almost every scenario, we're hooking our actions only up to "Touch Up Inside". This allows the user to consider whether or not they want to really press the button. If they drag their finger off the button before letting go, the action doesn't fire, because the "up touch" gesture happened outside the bounds of the object.

But here, we want to actually hook our button's "touch down" event up. This is when we'll display the label.

Let's go ahead and create a "touch down" event and a "touch up inside" event:

Swift

@IBAction func buttonTouchDown(sender: UIButton) {
    self.myLabel.hidden = false
}

@IBAction func buttonTouchEnded(sender: UIButton) {
    self.myLabel.hidden = true
}

Objective-C

- (IBAction)buttonTouchDown:(UIButton *)sender {
    self.myLabel.hidden = NO;
}

- (IBAction)buttonTouchEnded:(UIButton *)sender {
    self.myLabel.hidden = YES;
}

So far, buttonTouchEnded is set up completely normally, and buttonTouchDown was set up by selecting "touch down" from the "Event" list.

We can always verify what our control is hooked up to by right clicking it in the interface builder:

Button sent events

But this menu is useful for more than simply checking what we've already hooked up. From here, we can hook up any of the other actions to our existing @IBAction methods simply by clicking in the circle and dragging to the existing method.

So we obviously want the label to disappear if we stop pressing the button, a normal touch up like you'd hook up any other button. The only question remaining is, what exact behavior do you want?

If you want the label to disappear only when the finger is lifted, no matter where the finger goes, then we must also hook up "touch up outside".

If you want the label to disappear when the user drags their finger off the button, then we should hook up the "touch drag exit" action.

We also probably want to hook up the "touch cancel" action, which would occur if some sort of system event (perhaps an incoming phone call) cancels the touch.

This Stack Overflow answer elaborates on the differences between the action options we have, so you can craft the behavior exactly how you need it.

Anyway, once we decide which actions we want to hook up to which methods, bring up that right click menu and click-drag from the circles to the methods:

Hooking up "Touch Cancel" to buttonTouchEnded(sender:)

0
Duncan C On

The easiest thing to do would be to add an action to the touchDown event and a separate action to touchUpInside and touchUpOutside.

Show the label on the touchDown action and hide it on the touchUpInside / touchUpOutside action. (and for completeness, on touchCancel, as suggested by nhgrif in his very thorough answer.)

A long press gesture recognizer won't work in this situation. You could create a custom gesture recognizer that triggered one event on touch and another event on release, and use that. It's actually not that hard to do.

EDIT

I just uploaded a demo project to GitHub called "MorphingButton" (link) that I created for another question here on Stack Overflow.

That project now shows a label on touching the app button and hides the label when you release the button.

The project is a hybrid Swift/Objective-C project that shows how to do the button morphing and label showing/hiding in both languages. It has a tab bar with a Swift tab and an Objective-C tab.