Jay Taylor
Jay Taylor

Reputation: 51

Objective C - Help with changing background color when UIButton is pressed

I am new to programing and any help is appreciated. I am trying to change the background color of a button once it has been pressed. I have tried setBackgroundColor without success. I am not sure that it is compatible with UIButton. Is there any way to programatically accomplish such a task? All thoughts and suggestions are appreciated.

Upvotes: 0

Views: 5769

Answers (5)

xarly
xarly

Reputation: 2144

I have created a subclass which get background color and creates an UIImage for each state. For me it's more useful a subclass instead a category, so that's up to you.

@implementation ROCRoundColorButton

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
        UIColor *darkColor;
        darkColor = [self darkColorFromBackgroundColor];

        [self setBackgroundImage:[self imageWithColor:self.backgroundColor withSize:self.frame.size] forState:UIControlStateNormal];
       [self setBackgroundImage:[self imageWithColor:darkColor withSize:self.frame.size] forState:UIControlStateSelected];
    }
    return self;
}

-(id)initWithCoder:(NSCoder *)aDecoder
{

   self = [super initWithCoder:aDecoder];
   if (self) {

       UIColor *darkColor;
       darkColor = [self darkColorFromBackgroundColor];

       [self setBackgroundImage:[self imageWithColor:self.backgroundColor withSize:self.frame.size] forState:UIControlStateNormal];
       [self setBackgroundImage:[self imageWithColor:darkColor withSize:self.frame.size] forState:UIControlStateSelected];
   }
   return self;
}

/*
 // Only override drawRect: if you perform custom drawing.
 // An empty implementation adversely affects performance during animation.
  - (void)drawRect:(CGRect)rect
 {
 // Drawing code
 }
*/

#pragma mark -
#pragma mark Private methods

- (UIColor *)darkColorFromBackgroundColor
{
const float* components = CGColorGetComponents( self.backgroundColor.CGColor );
CGFloat red     = components[0];
CGFloat green = components[1];
CGFloat blue   = components[2];
CGFloat alpha = components[3];
if (red > 0) {
    red -= 0.1;
}
if (green > 0) {
    green -= 0.1;
}
if (blue > 0) {
    blue -= 0.1;
}
UIColor *darkColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
return darkColor;
}

- (UIImage *)imageWithColor:(UIColor *)color withSize:(CGSize)size
{
UIGraphicsBeginImageContext(size);
CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetFillColorWithColor(context, [color CGColor]);
//CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height));
UIBezierPath *roundedRect = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, size.width, size.height) cornerRadius:5];
[roundedRect fillWithBlendMode: kCGBlendModeNormal alpha:1.0f];
[color setFill]; 

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;
}

In fact, you can use it in the storyboard, changing the class and setting de background color in the view.

Upvotes: 1

Chris Mitchelmore
Chris Mitchelmore

Reputation: 6176

Ive just been having the same issue and ended up using a UIButton subclass to tackle the issue. I used gradients simply because it looked a bit better if you have no need for them you can simply remove them. I have explained the process I used and included the full code at the bottom of the post.

  • Firstly add properties for the layers.I created two layers one for the base gradient and one for a gloss to add a little bit of style.

     @interface gradientButton()
     @property (nonatomic, strong) CAGradientLayer* gradientLayer;
     @property (nonatomic, strong) CAGradientLayer* glossyLayer;
     @end
    
  • Then either in -(void)awakeFromNib or in -(id)initWithFrame:(CGRect)frame ,depending on if you will load from storyboard or code respectively, configure the gradients and add the layers, round your corners off and customize the font highlight color.

     -(void)awakeFromNib
     {
         _gradientLayer = [[CAGradientLayer alloc] init];
         _gradientLayer.bounds = self.bounds;
         _gradientLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
         [self.layer insertSublayer:_gradientLayer atIndex:0];
    
        self.layer.cornerRadius = 5.0f; 
        self.layer.masksToBounds = YES;
        self.layer.borderWidth = 1.0f;
    
        _glossyLayer = [[CAGradientLayer alloc] init];
        _glossyLayer.bounds = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height/2);
        _glossyLayer.position = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/4);
        [self.layer addSublayer:_glossyLayer];
    
         [self setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
         [self setTitleColor:[UIColor yellowColor] forState:UIControlStateHighlighted];
    
     }
    
  • Next, override - (void)drawRect:(CGRect)rect to apply your layers and define your colors.

     #define GRADIENT_TOP [UIColor colorWithRed:38.0/255.0 green:78.0/255.0 blue:54.0/255.0 alpha:1]
     #define GRADIENT_BOTTOM [UIColor colorWithRed:44.0/255.0 green:71.0/255.0 blue:56.0/255.0 alpha:1]
     #define GLOSS_TOP [UIColor colorWithRed:0.70f green:0.70f blue:0.70f alpha:0.95f]
     #define GLOSS_BOTTOM [UIColor colorWithRed:0.70f green:0.70f blue:0.70f alpha:0.35f]
     #define GRADIENT_SELECTED_TOP [UIColor colorWithRed:138.0/255.0 green:178.0/255.0 blue:154.0/255.0 alpha:1]
     #define GRADIENT_SELECTED_BOTTOM [UIColor colorWithRed:114.0/255.0 green:171.0/255.0 blue:156.0/255.0 alpha:1]
    
    
    
     - (void)drawRect:(CGRect)rect
     {
    
         [_gradientLayer setColors:@[(id)[GRADIENT_TOP CGColor],(id)[GRADIENT_BOTTOM CGColor]]];
    
         [_glossyLayer setColors:@[(id)[GLOSS_TOP CGColor], (id)[GLOSS_BOTTOM CGColor]]];
         [super drawRect:rect];
     }
    
  • Finally, and the bit we've all been waiting for, override -(void)setHighlighted:(BOOL)highlighted{ so we can apply the highlight effect were looking for.

     -(void)setHighlighted:(BOOL)highlighted{
         [super setHighlighted:highlighted];
         if(highlighted)
             [_gradientLayer setColors:@[(id)[GRADIENT_SELECTED_TOP CGColor],(id)[GRADIENT_SELECTED_BOTTOM CGColor]]];
         else
             [_gradientLayer setColors:@[(id)[GRADIENT_TOP CGColor],(id)[GRADIENT_BOTTOM CGColor]]];
     }
    
  • There we have it, now just drag out a UIButton modify the class and your all good. Heres the full Implementation so you can copy it straight out. http://pastebin.com/nUVeujyp

Upvotes: 2

Blitz
Blitz

Reputation: 5671

I woudl suggest creating a simple image that contains the background color you want and setting that via the existing methods in the UIButton. (check Wrights Answer for the doc link).

UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
NSString* fileLocation = [[NSBundle mainBundle] pathForResource:@"buttonBG" ofType:@"png"];
UIImage* bgImage = [UIImage imageWithContentsOfFile:fileLocation];
if (bgImage != nil) { // check if the image was actually set
  [button setBackgroundImage:bgImage forState:UIControlStateHighlighted];
} else {
  NSLog(@"Error trying to read the background image");
}

That should do the trick. There might be an even better way to create the necessary image on the fly, but that's stuff I'm not firm in.

[edit: a bit more verbose code ]

Upvotes: 3

Hack Saw
Hack Saw

Reputation: 2781

Assuming you have an unadorned custom button with a title of "On" for the normal state:

- (IBAction) toggleButtonState {
    if ([toggleButton titleForState:UIControlStateNormal] == @"On") {
        [toggleButton setTitle: @"Off" forState:UIControlStateNormal];
        [toggleButton setBackgroundColor:[UIColor redColor]];
    }
    else {
        [toggleButton setTitle: @"On" forState:UIControlStateNormal];
        [toggleButton setBackgroundColor:[UIColor greenColor]];

    }
}

All the other buttons have an image placed in front of the view, so at most you'll see the corners change if the image doesn't completely fill the space.

I'd also suggest using an image, but for learning purposes, this will work.

Upvotes: 2

WrightsCS
WrightsCS

Reputation: 50707

Check out the UIButton Class Reference.

Regular UIButtons do not have the backgroundColor option.

My suggestion would to use the UISegmentedControl, which has the tinColor option.

Upvotes: 1

Related Questions