As we know, UIButton
provide the image setters based on UIControlState
. But seems it doesn't provide to set background color based on UIControlState
.
How to do it?
Asked
Active
Viewed 1.1k times
1

Haroldo Gondim
- 7,725
- 9
- 43
- 62

childrenOurFuture
- 1,889
- 2
- 14
- 23
2 Answers
12
Get an UIImage
from UIColor
, use that image as background image for the button.
- (UIImage *)imageWithColor:(UIColor *)color
{
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
[button setBackgroundImage:[self imageWithColor:[UIColor lightGrayColor]] forState:UIControlStateNormal];
[button setBackgroundImage:[self imageWithColor:[UIColor redColor]] forState:UIControlStateHighlighted];

gabbler
- 13,626
- 4
- 32
- 44
-
1This answer assumes that the asker wants a solid color as the entire button. What he asked for was background color changing by state, which for example could make an icon turn different colors based on the background color. – robertfiorentino Mar 24 '17 at 18:26
5
Yes that's correct... you need to handle this in a UIButton
subclass.
This is a StyleKitButton
, UIButton
subclass I use. It stores the background colours for each mode in a dictionary, then some fancy handling for touches to transition correctly.
Usage
StyleKitButton *button = [[StyleKitButton alloc] init];
button.layer.borderColor = [UIColor blue].CGColor;
[button setTitleColor:[UIColor white] forState:UIControlStateNormal];
[button setBackgroundColor:[UIColor blue] forState:UIControlStateNormal];
[button setTitleColor:[UIColor white] forState:UIControlStateHighlighted];
[button setBackgroundColor:[UIColor purple] forState:UIControlStateHighlighted];
Class:
#import <UIKit/UIKit.h>
@interface StyleKitButton : UIButton
@end
//------------------------------------------------------
#import "StyleKitButton.h"
@interface StyleKitButton()
@property (nonatomic, strong) NSMutableDictionary *backgroundColors;
@end
@implementation StyleKitButton
#pragma mark - Background Colors
- (void)setBackgroundColor:(UIColor *)backgroundColor forState:(UIControlState)state {
if (!self.backgroundColors) {
self.backgroundColors = [[NSMutableDictionary alloc] init];
}
if (backgroundColor) {
self.backgroundColors[@(state)] = backgroundColor;
}
if (state == UIControlStateNormal) {
self.backgroundColor = backgroundColor;
}
}
- (void)transitionBackgroundToColor:(UIColor*)color {
CATransition *animation = [CATransition animation];
animation.type = kCATransitionFade;
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[self.layer addAnimation:animation forKey:@"EaseOut"];
self.backgroundColor = color;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
UIColor *selectedColor = self.backgroundColors[@(UIControlStateHighlighted)];
if (selectedColor) {
[self transitionBackgroundToColor:selectedColor];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
UIColor *normalColor = self.backgroundColors[@(UIControlStateNormal)];
if (normalColor) {
[self transitionBackgroundToColor:normalColor];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
UIColor *normalColor = self.backgroundColors[@(UIControlStateNormal)];
if (normalColor) {
[self transitionBackgroundToColor:normalColor];
}
}
@end

Gavin Bunney
- 1,240
- 1
- 12
- 12
-
Great answer, however I think it is a bit over complicated of a solution. It is possible to do this without subclassing a UIButton, and they never asked anything about animating the colour, so I think the part of your answer is a bit redundant. – David Williames Mar 11 '16 at 02:49