3

I'd like to set the title of a UIButton via code. I find myself having to call -[UIButton setTitle:forState:] for UIControlStateNormal, UIControlStateHighlighted, UIControlStateDisabled, UIControlStateSelected. And that doesn't even take into account all of the combinations of these states together.

Needless to say, this is tiresome. Is there a single call I can make that will set one string as the title for all of the states? (Since, I assume that in 95% of the cases, that's the desired behavior?)

Justin Johnson
  • 30,978
  • 7
  • 65
  • 89
Greg Maletic
  • 6,225
  • 8
  • 54
  • 73

4 Answers4

9

Yes, you certainly can. From the docs:

In general, if a property is not specified for a state, the default is to use the UIControlStateNormal value. If the value for UIControlStateNormal is not set, then the property defaults to a system value. Therefore, at a minimum, you should set the value for the normal state.

So just set the title for UIControlStateNormal and you're golden.

Mark
  • 1,746
  • 2
  • 18
  • 19
Shaggy Frog
  • 27,575
  • 16
  • 91
  • 128
  • 5
    In practice, I've found situations where it seems that's not true: text mysteriously disappearing when a button is clicked on, etc. That said, I'm not sure I can recreate those situations. If I discover a problem, I'll post it here. Thanks! – Greg Maletic Mar 19 '10 at 18:09
7

Like Mr./Ms. Frog says, setting the title for UIControlStateNormal will usually do the trick. The only exception is if titles are already set for other states. UIControlState is a mask, so you can cover your butt like so:

[button setTitle:@"Title" forState:UIControlStateNormal|UIControlStateHighlighted| UIControlStateDisabled|UIControlStateSelected]

If you're trying to be concise:

#define kAllControlStates (UIControlStateNormal|UIControlStateHighlighted| UIControlStateDisabled|UIControlStateSelected)
[button setTitle:@"Title" forState:kAllControlStates];

Or concise and opaque:

[button setTitle:@"Title" forState:0xffff];

Update: I should have tested this before answering. It turns out a mask like UIControlStateHighlighted|UIControlStateDisabled indicates the state when the control is both highlighted and disabled. I had incorrectly assumed that that mask indicates "highighted or disabled". To conclude, you're better off with Mr. Frog's answer.

Tom
  • 3,831
  • 1
  • 22
  • 24
  • 4
    I found this didn't work for me. Text didn't show up on the button. I wonder if it's because UIControlStateNormal is equal to 0, making it fairly useless in a bit mask? – George Sealy Apr 14 '10 at 21:22
  • @George: You're right. Looks like my answer was incorrect. I'll add a note. – Tom Apr 14 '10 at 23:59
0

Create a category method for UIButton that sets it for all the states at once.

brant
  • 369
  • 3
  • 8
0

Although falling back to the values for the UIControlStateNormal state is probably good enough 99% of the time, I've come up with a solution to this problem for the 1% use case. (I have application defined states in a subclass which means falling back to the normal state would be incorrect.)

I'm posting it here for completeness, even though the answer has already been accepted. Basically it sets the attribute for the state plus every combination of individual additional states you specify.

@interface UIButton (AdditionalStates)
- (void)setTitle:(NSString *)title forState:(UIControlState)state additionalStates:(UIControlState)additionalStates;
@end

@implementation UIButton (AdditionalStates)

- (void)setTitle:(NSString *)title forState:(UIControlState)state additionalStates:(UIControlState)additionalStates
{
    [self setValue:title forKey:@"title" state:state additionalStates:additionalStates mask:(1 << 0)];
}

- (void)setValue:(id)value forKey:(NSString *)key state:(UIControlState)state additionalStates:(UIControlState)additionalStates mask:(NSUInteger)mask(UIControlState)additionalStates
{
    if (additionalStates == 0) {
        [self setValue:value forKey:key state:state];
        return;
    }

    // Iterate over each 'on' bit in additionalStates, starting from the mask bit
    while (mask > 0) {
        if (additionalStates & mask) {
            // Delete the current bit from additionalStates
            NSUInteger reducedAdditionalStates = (additionalStates ^ mask);

            // Set the title for combinations of the remaining additional states with and without the mask bit
            [self setValue:value forKey:key state:(state | (additionalStates & mask)) additionalStates:reducedAdditionalStates mask:(mask << 1)];
            [self setValue:value forKey:key state:state additionalStates:reducedAdditionalStates mask:(mask << 1)];
        }
        mask = (mask << 1);
    }
}

- (void)setValue:(id)value forKey:(NSString *)key state:(UIControlState)state
{
    if ([key isEqualToString:@"title"]) {
        [self setTitle:value forState:state];
        return;
    }
}

@end
jamesmoschou
  • 1,173
  • 8
  • 15