UIButton disabled in IBAction re-enables itself - ios

I have a UIButton that is linked to an IBAction in a UIView. Within this IBAction, I both change the text of the UIButton's titleLabel and disable the UIButton. However, I've found that when the action fires, the button disables itself and changes its text for a split second before re-enabling itself. It's almost like it's happening just while the button is pressed, then it undoes itself. Could someone help with this? If it's useful, I'm on the latest Xcode and iOS 8 SDK.
//this is the IBAction...it happens, but the enabled property and text change quickly undoes itself.
#IBAction func solvePuzzle(sender: AnyObject) {
self.activity.startAnimating()
self.solveButton.enabled = false
self.solveButton.titleLabel?.text = "Solving..."
}

The text of the button should not be set like that. I am not very familiar with swift, but the right method should look something like:
self.solveButton.setTitle("Solving...", forState:UIControlState.Normal);
And also make sure that the method is called on the touchUpInside action.

Related

Why is UIButton.titleLabel?.text always switching back after I changed it in Swift 5 (UIKit)?

I ran into an issue with my UIButton.
After the User presses the button, it activates an IBAction which is supposed to change the titleLabel.text of my UIButton.
self.btnAppleHealthKit.titleLabel?.text = "Already pressed."
Whenever I press the button, the text changes for about a quarter second to "Already pressed", but switches back immediately to the previous text.
Important Note: The whole thing is inside a completion handler but I wrapped it into DispatchQueue.main.async { }
Can you guys think of an idea why this error appears?
Thanks for your help in advance.
It seems, UIButton does not allow to configure text or color of titleLabel.
From apple doc.s
Do not use the label object to set the text color or the shadow color.
Instead, use the setTitleColor(:for:) and setTitleShadowColor(:for:)
methods of this class to make those changes. To set the actual text of
the label, use setTitle(_:for:) (button.titleLabel.text does not let
you set the text).

UIButton: when isHighlighted = true, I can only call a function by swiping my finger

Need some of your great knowledge :)
I wrote a subclass of UIButton (CustomWideButton.swift) without using a UIButton object. I did it this way because it's more flexible for the types of buttons I need to create.
There is a strange thing and I don't know if it is a normal behaviour.
var isHighlighted is called when tapping the button area which is normal. So if I write something like this:
var isHighlighted {
didSet {
print("I am Highlighted")
animateHighlight()
}
}
I will see in the console "I am highlighted", but it won't call animateHighlight() unless I slightly start swiping my finger on the button. If I do so, then animateHighlight() works.
I posted a sample project on BitBucket so it'll be easier for you to understand the issue I'm facing:
https://bitbucket.org/stephaneDepoilly/stackohighlightedbutton
Direct link for zip: https://bitbucket.org/stephaneDepoilly/stackohighlightedbutton/get/ee4fc398f475.zip
I'm sorry if the custom button code looks overkill, it's because I partially extracted it from my project and we're using MVVM.
Thanks in advance for your help!
Your debugging messages are misleading you. I replaced your print with:
NSLog("isHighlighted on \(title) set to \(isHighlighted)")
And I added as the first line in animateHighlight():
NSLog("animateHighlight enter: triggered by isHighlighted on \(title) set to \(isHighlighted)")
And I got:
2017-08-27 21:57:34.870 StackO_HighlightFunctionCall isHighlighted on [...LOGIN...] set to true
2017-08-27 21:57:34.871 StackO_HighlightFunctionCall animateHighlight enter: triggered by isHighlighted on [...LOGIN...] set to true
2017-08-27 21:57:35.000 StackO_HighlightFunctionCall isHighlighted on [...LOGIN...] set to false
2017-08-27 21:57:35.000 StackO_HighlightFunctionCall animateHighlight enter: triggered by isHighlighted on [...LOGIN...] set to false
So:
1) animateHighlight is indeed being called when you tell it to be called. Use the DebuggerForce!
2) isHighlighted state switches very rapidly (0.13 sec) back to false after being set to true. Did you expect that?
3) animateHighlight is buggy and doesn't produce any visible change. If you trace through your code carefully you'll see setupUI() gets called right after updating the label's text. This is because you are calling setupUI() from layoutSubviews(). layoutSubviews gets called all the time during runtime when anything about a view changes that could possibly affect subviews. setupUI should get called only when the view is added to its superview, e.g. at viewDidLoad()
The reason the swipe works is that layoutSubviews() is delayed until you finish swiping, because it's the .touchUpInside event that triggers the tap action, but isHighlighted is triggered by hidden UIButton .touchDownInside handling!

Swift - how to hide unknown button?

I have 4 buttons. Each of them represent 1 answer for question in trivia game. In different screens i have different questions and buttons with different answers. I have a mode, when when player can make a mistake, this is enabled by pressing the fifth button. So, when this mode is enabled i show alert and i need to hide button with wrong question which was pressed. Everything that i know about - that it is member of array with buttons with wrong questions. How can I tell the alert which button to hide on completion ?
Attach them all to an IBAction that takes a UIButton and then hide the one that was pushed by adding the line
sender.hidden = true
or disable it by adding
sender.enabled = false
Do you mean you wish to know if the button has been pressed? Well if you connect that UIButton to that IBAction, that IBAction will be fired each time the button is pressed. You could insert and NSLog("button press") line inside the IBAction to see that it is pressed.

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

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.
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:
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:
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:
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.

Creating a custom toggle with UIButton in Interface Builder

Is this possible? It seems shoddy for it not to be.
I'm trying to create a toggle button (not a UISwitch) in IB. For example a mute button, when muted would have some indication that sound is disabled, when you hit it, that indicator disappears (but still the same underlying graphic), and toggles between these states each time it is pressed.
This functionality can be achieved using the selected property, however you can't change the Selected AND Highlighted property in IB like you can in code, so whenever the button is pressed, no matter the state, the highlighted image is the same, which looks terrible and glitchy.
Is there a way to fix this with just IB, or do I have to make a custom class to avoid manually loading in all these buttons?
Have you thought about subclassing UIButton to add in the things you need?

Resources