Text change on UIButton doesn't stick - cocoa-touch

I have an UIButton in my View that says "STOP". When pressed, it should (stop the playback, of course, and) change its label to "RTN TO ZERO". This is straightforward:
stopButton.titleLabel.text = #"RTN TO ZERO";
However, the change appears only for a split second. It doesn't stick. I assume that the button (which gets highlighted when pressed) accepts and displays the new label, but somehow the highlight is reversed only later, restoring the button to the look it had before it was pressed, not honoring the label text change.
The button is conceived in IB, not programmatically.
I feel stupid. Can someone please point me in the right direction?

In the button handler, try this:
[stopButton setTitle:#"RTN TO ZERO" forState:UIControlStateNormal];
Instead of directly changing text property of titleLabel use setTitle:forState: method to set the title in different states. Please check the manual for the details of available states.

Swift version
myButton.setTitle("button text", for: UIControl.State.normal)
Use setAttributedTitle:for for attributed text. See here for how to make attributed strings in Swift.

Related

Setting the text on UIButtonLabel on a PLUICameraViewController

I'm trying to set the text of the "Retake" and "Use" buttons on the PLUICameraViewController. I've programmatically navigated through the view hierarchy and found a few UIButtonLabel objects. Logging the text of these shows what I expect: "Retake", "Cancel" etc. However setting the text doesn't work. The buttons just keep their original text. Here's what I've tried:
if (q is a subclass of UIButtonLabel)
if ([q respondsToSelector:#selector(setText:)])
[q performSelector:#selector(setText:) withObject:#"zzz"];
The code runs w/o crashing. Also respondsToSelector is returning YES. How can I make the text on the buttons update?
By the way I'm aware of other approaches involving custom buttons, my own views etc. I'm really curious from an Objective-C/runtime/iOS perspective why the above code doesn't work.
Also note I'm doing this in
navigationController:willShowViewController:viewController:animated:
In this case, I don't think it's an issue of Private APIs, per se. This is just the way UIButton works.
Yes, the title of the button is a UILabel, and in practice, it is probably/currently an instance of the private class UIButtonLabel. But, the way Apple intends for you to change the title text is to use the methods in UIButton itself:
[self.button setTitle: #"newTitle" forState: UIControlStateNormal];
[self.button setTitle: #"newTitle" forState: UIControlStateSelected];
instead of trying to drill down into the button's subview heirarchy, find a button label, and call setText:.
Here's the relevant API documentation
As to why it doesn't work, I suppose that's because Apple wants it that way.
For one, changing a button's title is expected to be a normal use case. So, for convenience, they probably wanted to give you an easy method to call, directly in the UIButton interface. If they forced you do drill down into the view hierarchy, not only would you have to write more code, but it makes it a little harder for Apple to change the underlying implementation of a button. They may want to preserve the ability to change it later, and for that, it's better for them to keep some sort of wrapper APIs at the UIButton level.
Also, if you directly change the text on the button label, you are circumventing their design, where the label text depends on the button state (e.g. normal, highlighted, selected, etc.) Even though most people probably use the same button text for all states, the design allows for state-dependent text, and therefore, hiding the underlying UIButtonLabel helps enforce this design.
That's my guess as to their motivation.
So, to enforce this, it's entirely possible that in their implementation of UIButtonLabel setText:, they decline to update the text after the button has been initialized. After that, you have to use the setTitle:forState: method.

UILabel with more... text

I have a text with multiple lines but at the end I want to add the phrase "more..." if the user press the more... word than the system it suppose to display the rest of the paragraph.
How can I do that?
one way is: use a UILabel to display a short text
put a UIButton under that with "show more" make settings to button to look like a UILabel
catch the action of the button, and remove the button and display a multines text and change the size of the UILabel.
This isn't the right approach for novice programmers, I hope I have helped with an idea.
You could use a UITextView that contains the limited text and add a UITapGestureRecognizer that when tapped, removes the gesture and adds text to the textview.
There is no particularly easy way, built-in way to do it. If you want to implement it yourself, your best bet is to use a UITextView instead of a UILabel. UITextView conforms to the UITextInput protocol, so when you detect a tap on the text view, you can use closestPositionToPoint: and related messages to figure out which part of the string was tapped.
Instead of doing it yourself, you could use TTTAttributedLabel or OHAttributedLabel. Both of these have built-in support for detecting taps on links. I haven't used either, so I can't advise you on which is better. There are probably other free solutions available, but those were easy to find.

How to add a second UILabel to a UIButton, configurable per UIControlState

I want to display 2 strings (at different positions in the button) with different fonts and colors (I'm using the button's setTitle for one, and I need another one), and some attributes must be changed based on the current UIControlState (like the color).
So, I'm searching the best way to add a second label to a UIButton.
I need the label to be configurable per UIControlState (I want a different color for UIControlStateNormal and UIControleStateHighlighted for example).
I've tried the following approches:
Subclass a UIButton and use drawRect: while not recommended (and I now understand why), I don't think it's even possible, it looks like the button's drawRect method is called (and after the one of my subclass) even if I don't call super.
Create a new UILabel and add it as a subview to my button: this is working quite well, except I don't know how to change the color when the UIControlState of the button is changing
Create a new layer and use drawLayer: I don't know how to get the drawLayer method to be called every time the button state is changing (my drawLayer only gets called once, when I use setNeedsDisplay just after adding my layer to the button)
Is there another way to achieve what I'm trying to do, or maybe one of those solutions might work (with a few tweaks)?
Thanks!
The second of your approach works fine. Just add 2 targets: First update to "normal state" target using "all touch events". Second update to "highlighted" using "touch down" event.
If the states are not only changed by touches and want to handle this more generally, Id suggest multithreading. All you really need is calling performSelectorInBackground when initializing all this elements (the selector updates label according to button state) and then again call same performSelectorInBackground on the end of "update label" method, creating an infinite loop.
Ok, I think I found a working solution (for my problem at least).
I'm subclassing the UIButton class (it works for me, since I'm using a custom drawn button anyway), and I override the titleRectForContentRect method that gets called everytime the title has to be displayed (including after a state change, just before display).
I added an UILabel to the button's view to display the second string I want, and during the titleRectForContentRect, I compute the correct frame location for my label, I update my label's text font and color based on the button's state (self.state), and that's all I need.

How to focus on an alternate label using cocoa?

I'm still a noob to iPhone development so sorry for the dumb question. I'm creating an app that has a custom numeric keyboard. I have an IBAction 'buttonDigitPressed' that when a digit is pressed it will simply add the digit to a UILabel. Now I have another label that I wish to do the same yet I'm not sure how to gain 'focus' of that particular label. I placed an invisible button over the second label so when pressed hopefully I can call an action to switch the keyboard from the first label to the second label. Yet I have no clue how to accomplish this. Any help would be greatly appreciated!
First of all, having to put an invisible button over the UILabel is skanky. If you want the user to be able to tap a number to mean "next time I hit a digit, append its value to this number", you'll probably be happier if you just use a UIButton right from the start. You can make a UIButton that looks pretty much like a UILabel (i.e. it has no border or background color). To set a UIButton's title in code, call setTitle:forState: with the UIControlStateNormal state. So now you've got tappable numbers, i.e. these UIButtons.
Okay, so now let's pretend you've got, say, three UIButtons. You need to use an instance variable here. So, each button will have an action - let's say doButton:(id)sender. So doButton will store the value of sender (the button that was just pressed) in the instance variable. Now your buttonDigitPressed action just looks in that instance variable to learn which button to append to. That's part of the power of instance variables - they give a method in a class a place to store a value where another method in the same class can get at it.

UILabel inside a UIToolbar using IB is invisible on run, how fix?

I want to show a total inside a toolbar. I put in IB the UILabel on top of the toolbar .
However, when I run the app, the UILabel is totally invisible (but can set values on code fine).
The most bizarre thing is that in other form, all work fine. I don't see why in one form work but not in another...
Any idea in how fix this? Or why is this behaviour happening?
Don't use a UILabel.
Use a UIBarButtonItem. Then set it to style: plain. It looks like a label, but it actually borderless button. This is the general practice of displaying text on a bar.
You can also create UIBarButtonItem with a custom view in code. You are simple "wrapping" the UILabel in a UIBarButtonItem allowing you to add anything you want to a tool bar.
To add in response to comment:
Either way, you make the button "inactive" and it doesn't respond to touches. Even though it is a button, it doesn't appear to be one. This is how Apple expects to add views to a toolbar/navbar as apposed to "float things on top of it". It violates no HIG guidelines, much the opposite, it is a reccomended design technique.
To stop the glow:
Create the button programmatically, make sure it is disabled, add it to the bar, it should then be disabled, but not dim.
In IB, have you tried to select the label and use the "Bring to Font" menu item (under Layout)? It seems like you are trying to do something pretty standard.
When you try to set values, is the label coming up as nil or at address 0x0? It's possible that the label is there, but its text cannot be set because its instance is faulty (not properly connected in IB to the IBOutlet).... Just put a breakpoint on the line where you are trying to set the value(s) for the label, and verify that the label variable is not nil (or 0x0). If it's not, try setting the text and verify on the next line that its text was set properly.
drag a UIButton into your UIToolBar. Then uncheck User Interaction Enables for this button.
Customize your UIButton so that it will look like a UILabel. Hope this will help you.