Friday, June 25, 2010

Programmatic Gradient Buttons

type='html'>Thanks to a little insomnia, I decided to play around a little more with doing a programmatic gradient button. I started to create another gradient button, realized that the code was going to be 90% the same between the two style gradient buttons, so did a little refactoring. The result is a class you can subclass to easily make new gradient buttons. All you have to do is override three methods to specify the gradient to use when the button is in its normal state, the gradient to use when the button is in highlighted (pressed) state, and the corner radius. Here's what the alert-style button looks like now:

BlueGradientButton.h
#import <UIKit/UIKit.h>
#import "AbstractGradientButton.h"

@interface BlueGradientButton : AbstractGradientButton
{
}


@end


BlueGradientButton.m
#import "BlueGradientButton.h"

@implementation BlueGradientButton
- (CGGradientRef)createNormalGradient
{
CGFloat locations[3];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
NSMutableArray *colors = [NSMutableArray arrayWithCapacity:3];
UIColor *color = [UIColor colorWithRed:0.283 green:0.32 blue:0.414 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[0] = 0.0;
color = [UIColor colorWithRed:0.82 green:0.834 blue:0.87 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[1] = 1.0;
color = [UIColor colorWithRed:0.186 green:0.223 blue:0.326 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[2] = 0.483;

CGGradientRef ret = CGGradientCreateWithColors(space, (CFArrayRef)colors, locations);
CGColorSpaceRelease(space);
return ret;
}

- (CGGradientRef)createHighlightGradient
{
CGFloat locations[4];
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
NSMutableArray *colors = [NSMutableArray arrayWithCapacity:4];
UIColor *color = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[0] = 0.0;
color = [UIColor colorWithRed:0.656 green:0.683 blue:0.713 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[1] = 1.0;
color = [UIColor colorWithRed:0.137 green:0.155 blue:0.208 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[2] = 0.51;
color = [UIColor colorWithRed:0.237 green:0.257 blue:0.305 alpha:1.0];
[colors addObject:(id)[color CGColor]];
locations[3] = 0.654;

CGGradientRef ret = CGGradientCreateWithColors(space, (CFArrayRef)colors, locations);
CGColorSpaceRelease(space);
return ret;
}

- (CGFloat)cornerRadius
{
return 7.0;
}

@end



Adding new gradient buttons is relatively simple, since all the heavy drawing is handled in the superclass based on the values you return in these three methods. You can check out the sample project that has two gradient buttons: one that simulates the alert style button and which also works for regular bar buttons, and one that simulates the red delete button. I'll likely add more styles later.

One important notice - the CFGradientRef returned by the two methods should not be released, the super class will release it when it's done. This is a bit of an oddity, but there is no CFGradientAutorelease() function, only a CFGradientRelease() function. I changed the name to start with "create". In the Core Foundation memory management rules, functions that use create return an object with retain count of 1. There probably is a more elegant way to deal with this situation, but none occurred to me and I didn't want to have to mess around with a callback to release the memory given how straightforward the usage is here.

You can download the project here. I've also added the project to Google Code if anyone wants to contribute additional elements.

No comments:

Post a Comment