Reputation: 1568
This has been a very odd process.
I have an IBOutletCollection of UIButtons. I loop through the collection and create them like this (the displayHourButtons
is called from viewWillAppear
):
- (void)displayHourButtons
{
// Counter
NSUInteger b = 0;
// Set attributes
UIFont *btnFont = [UIFont fontWithName:@"Metric-Semibold" size:13.0];
UIColor *btnTextColor = [UIColor colorWithRed:(147/255.0f) green:(147/255.0f) blue:(147/255.0f) alpha:1.0];
NSNumber *btnTracking = [NSNumber numberWithFloat:0.25];
NSMutableParagraphStyle *btnStyle = [[NSMutableParagraphStyle alloc] init];
[btnStyle setLineSpacing:2.0];
NSDictionary *btnAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
btnFont, NSFontAttributeName,
btnTextColor, NSForegroundColorAttributeName,
btnTracking, NSKernAttributeName, nil];
// CREATE THE BUTTONS
for (UIButton *hourButton in hourButtons) {
// I'm using the attributed string for something else
// later in development that I haven't got to yet.
// I simplified the string for this example's sake.
NSString *btnTitleText = [NSString stringWithFormat:@"Button %lu", (unsigned long)b];
NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc]
initWithString:btnTitleText
attributes:btnAttrs];
[attributedText addAttribute:NSParagraphStyleAttributeName
value:btnStyle
range:NSMakeRange(0, btnTitleText.length)];
CALayer *btnLayer = [hourButton layer];
[btnLayer setMasksToBounds:YES];
[btnLayer setCornerRadius:19.0f];
[hourButton setTag:b];
[hourButton setContentEdgeInsets:UIEdgeInsetsMake(5.0, 1.0, 0.0, 0.0)];
[hourButton setAttributedTitle:attributedText forState:UIControlStateNormal];
[hourButton setContentHorizontalAlignment:UIControlContentHorizontalAlignmentCenter];
[hourButton setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
hourButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
[hourButton addTarget:self action:@selector(showHour:) forControlEvents:UIControlEventTouchUpInside];
b++;
}
}
When one of the buttons is clicked, per the action showHour:
is called:
- (IBAction)showHour:(id)sender
{
[self.hourButtons enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIButton *button = (UIButton *)obj;
if (button != sender && button.enabled) {
// This is applied. I know because I tested it with redColor
[button setBackgroundColor:[UIColor clearColor]];
// Doesn't change, stays the gray set initially
[button setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
}
else {
// This is applied
[button setBackgroundColor:[UIColor colorWithRed:(169/255.0f) green:(234/255.0f) blue:(255/255.0f) alpha:1.0]];
// This is not
[button setTitleColor:[UIColor whiteColor] forState:(UIControlStateNormal | UIControlStateSelected | UIControlStateHighlighted)];
}
}];
// displayHour uses the tag to change labels, images, etc.
[self displayHour:(long int)[sender tag]];
}
I tried all sorts of crazy things to get the UIImage to be in a selected state, but nothing worked. This enumerateObjects deal is the only thing that has worked. That's why I say this has been an odd process. I guess buttons don't stay active indefinitely?
Anyways, MY QUESTION: Is there a certain reason why the title color isn't changing? Just the background? I suspect it has something to do with the background not being set initially, but I couldn't explain why.
Thanks!
UPDATED
Per @Timothy Moose's answer, below is the updated code.
- (IBAction)showHour:(id)sender
{
[self.hourButtons enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIButton *button = (UIButton *)obj;
// Grab the mutable string from the button and make a mutable copy
NSMutableAttributedString *attributedText = [[button attributedTitleForState:UIControlStateNormal] mutableCopy];
// Shared attribute styles
UIFont *btnFont = [UIFont fontWithName:@"Metric-Semibold" size:14.0];
NSNumber *btnTracking = [NSNumber numberWithFloat:0.25];
NSMutableParagraphStyle *btnStyle = [[NSMutableParagraphStyle alloc] init];
[btnStyle setLineSpacing:2.0];
// Since we can't set a color directly on a Attributed string we have
// to make a new attributed string.
if (button != sender && button.enabled) {
// Return to the default color
UIColor *btnTextColor = [UIColor colorWithRed:(147/255.0f) green:(147/255.0f) blue:(147/255.0f) alpha:1.0];
// Set up attributes
NSDictionary *btnAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
btnFont, NSFontAttributeName,
btnTextColor, NSForegroundColorAttributeName,
btnTracking, NSKernAttributeName, nil];
// Reapply the default color (for the one button that was changed to white)
[attributedText setAttributes:btnAttrs
range:NSMakeRange(0, attributedText.length)];
// Add line-height
[attributedText addAttribute:NSParagraphStyleAttributeName
value:btnStyle
range:NSMakeRange(0, attributedText.length)];
// Reset default attributes
[button setBackgroundColor:[UIColor clearColor]];
[button setAttributedTitle:attributedText forState:UIControlStateNormal];
}
else {
// Our new white color for the active button
UIColor *btnTextColor = [UIColor whiteColor];
// Set up attributes
NSDictionary *btnAttrs = [NSDictionary dictionaryWithObjectsAndKeys:
btnFont, NSFontAttributeName,
btnTextColor, NSForegroundColorAttributeName,
btnTracking, NSKernAttributeName, nil];
// Apply our new white color
[attributedText setAttributes:btnAttrs
range:NSMakeRange(0, attributedText.length)];
// Add line-height
[attributedText addAttribute:NSParagraphStyleAttributeName
value:btnStyle
range:NSMakeRange(0, attributedText.length)];
// Add new attributes for active button
[button setBackgroundColor:[UIColor colorWithRed:(169/255.0f) green:(234/255.0f) blue:(255/255.0f) alpha:1.0]];
[button setAttributedTitle:attributedText forState:UIControlStateNormal];
}
}];
[self displayHour:(long int)[sender tag]];
}
Upvotes: 11
Views: 14318
Reputation: 3853
An alternative to the above answers is to apply the text colour using string attributes. You can set a different NSAttributedString for each control state, so this works to achieve the same effect - the button text will change colour on select/highlight.
Example:
// We're assuming attributedString already exists - this is your completed attributed string so far
// We're going to copy this string into two more NS(Mutable)AttributedString variables - one for the "normal" state and one for the "highlighted" state
NSMutableAttributedString *normalAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
// Set the desired foreground color (in this case it's for the "normal" state) for the length of the string
[normalAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor blackColor] range:NSMakeRange(0,attributedString.length)];
// Rinse and repeat for the highlighted state
NSMutableAttributedString *highlightedAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString];
[highlightedAttributedString addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:NSMakeRange(0,attributedString.length)];
// Finally, we'll set these as the attributedTitles for the relevant control states.
[myButton setAttributedTitle:normalAttributedString forState:UIControlStateNormal];
[myButton setAttributedTitle:highlightedAttributedString forState:UIControlStateSelected];
[myButton setAttributedTitle:highlightedAttributedString forState:UIControlStateHighlighted];
Upvotes: 0
Reputation: 1
In my case, I am using XCode 7.x.
I faced up with the similar problem. After using NSAttributedString
let underlineAttribute = [NSUnderlineStyleAttributeName: NSUnderlineStyle.StyleSingle.rawValue]
let underlineAttributedString = NSAttributedString(string: "FILTER", attributes: underlineAttribute)
filterButton.setTitleColor(AppConfig.FOREGROUND, forState: .Normal)
filterButton.setAttributedTitle(underlineAttributedString, forState: .Normal)
the filterButton.setTitleColor(AppConfig.FOREGROUND, forState: .Normal) not get effected.
I change the Tint Color of the button in the Interface Builder (which is default as light blue). Now, it works for me now.
Upvotes: 0
Reputation: 6052
I created a custom class MyButton extended from UIButton
. Then added this inside the Identity Inspector
:
After this, change the button type to Custom:
Then you can set attributes like textColor
and UIFont
for your UIButton
for the different states:
Then I also created two methods inside MyButton
class which I have to call inside my code when I want a UIButton
to be displayed as highlighted:
- (void)changeColorAsUnselection{
[self setTitleColor:[UIColor colorFromHexString:acColorGreyDark]
forState:UIControlStateNormal &
UIControlStateSelected &
UIControlStateHighlighted];
}
- (void)changeColorAsSelection{
[self setTitleColor:[UIColor colorFromHexString:acColorYellow]
forState:UIControlStateNormal &
UIControlStateHighlighted &
UIControlStateSelected];
}
You have to set the titleColor
for normal, highlight and selected UIControlState
because there can be more than one state at a time according to the documentation of UIControlState
.
If you don't create these methods, the UIButton
will display selection or highlighting but they won't stay in the UIColor
you setup inside the UIInterface Builder
because they are just available for a short display of a selection, not for displaying selection itself.
Upvotes: 3
Reputation: 2973
I noticed this immediately. Just a simple error probably :)
Change
UIColor *btnTextColor = [UIColor colorWithRed:(147/255.f)
green:(147/255.f)
blue:(147/255.f) alpha:1.0];
to
UIColor *btnTextColor = [UIColor colorWithRed:(147/255.0f)
green:(147/255.0f)
blue:(147/255.0f) alpha:1.0];
The reason it wasn't changing is probably because it wasn't recognizing the UIColor
since you didn't have a full number in the division, since it was seeing (147/255.) instead of (147/255.0)
Upvotes: -2
Reputation: 1899
Also it is very important not to have the button on System style, just put it on custom... This is for similar questions, not for this particular question.
Upvotes: 20
Reputation: 9915
setTitleColor
doesn't have any effect when the title is an attributed string. Either use a plain NSString
or call setAttributedTitle
again after applying the desired color to the attributed string.
Upvotes: 20