iOS Colour Mixing Class
In order to vary colour between 2 or more colours according to a value we great a the following ColourMixer class.
We provide it with an array of boundaries and colours and then query it with a value to find our required colour.
This class supports 2 different mixing methods - discrete, where the outputs are not mixed, or gradient where mixing occurs.
ColourMixer.h
typedef enum {
ColourMixerGradient,
ColourMixerDiscrete
} ColourMixerType;
@interface ColourMixer : NSObject
@property (nonatomic, retain) NSArray *colours;
@property (nonatomic, retain) NSArray *boundaries;
@property (nonatomic, assign) ColourMixerType type;
- (UIColor *)colourForValue:(id)value;
@end
ColourMixer.m
#import "ColourMixer.h"
@implementation ColourMixer
@synthesize colours = _colours;
@synthesize boundaries = _boundaries;
@synthesize type = _type;
- (id)init {
self = [super init];
if(self) {
[self setDefaults];
}
return self;
}
-(void)dealloc
{
[_colours release], _colours = nil;
[_boundaries release], _boundaries = nil;
[super dealloc];
}
-(void)setDefaults
{
self.type = ColourMixerDiscrete;
self.colours = [[[NSArray alloc] initWithObjects:[UIColor redColor], [UIColor orangeColor], [UIColor greenColor], nil] autorelease];
self.boundaries = [[[NSArray alloc] initWithObjects:[NSNumber numberWithFloat:0.5], [NSNumber numberWithFloat:0.8], nil] autorelease];
}
- (UIColor *)colourForValue:(id)value
{
if(self.type == ColourMixerDiscrete) {
if (self.boundaries.count != (self.colours.count - 1)) {
return nil;
}
for (int i=0; i < self.boundaries.count; i++) {
if([value compare:[self.boundaries objectAtIndex:i]] == NSOrderedAscending) {
return [self.colours objectAtIndex:i];
}
}
return [self.colours lastObject];
} else {
// Must be a continuous gradient
if (self.boundaries.count != self.colours.count) {
return nil;
}
// If lower than first boundary then return first colour
if ([value compare:[self.boundaries objectAtIndex:0]] == NSOrderedAscending) {
return [self.colours objectAtIndex:0];
}
// If bigger than last boundary then return last colour
if ([value compare:[self.boundaries lastObject]] == NSOrderedDescending) {
return [self.colours lastObject];
}
// Otherwise, need to return a mixed colour
for (int i=1; i < self.boundaries.count; i++) {
if([value compare:[self.boundaries objectAtIndex:i]] == NSOrderedAscending) {
// So the mix should be between the (i-1)th and ith colours
double range = [[self.boundaries objectAtIndex:i] doubleValue] - [[self.boundaries objectAtIndex:(i-1)] doubleValue];
double ratio = ([value doubleValue] - [[self.boundaries objectAtIndex:(i-1)] doubleValue]) / range;
return [self mixColour:[self.colours objectAtIndex:(i-1)] andColour:[self.colours objectAtIndex:i] withRatio:ratio];
}
}
// Should never be able to get here...
return nil;
}
}
- (UIColor *)mixColour:(UIColor*)firstColour andColour:(UIColor*)secondColour withRatio:(double)ratio
{
if(ratio <= 0)
return firstColour;
if(ratio >= 1)
return secondColour;
/* There is a nicer way to do this in iOS > 5, but for backwards compatibility we do it this way */
CGColorRef colorref = [firstColour CGColor];
const CGFloat *components1 = CGColorGetComponents(colorref);
CGFloat r1 = components1[0];
CGFloat g1 = components1[1];
CGFloat b1 = components1[2];
CGFloat a1 = components1[3];
colorref = [secondColour CGColor];
const CGFloat *components2 = CGColorGetComponents(colorref);
CGFloat r2 = components2[0];
CGFloat g2 = components2[1];
CGFloat b2 = components2[2];
CGFloat a2 = components2[3];
CGFloat r3 = (r2 - r1) * ratio + r1;
CGFloat g3 = (g2 - g1) * ratio + g1;
CGFloat b3 = (b2 - b1) * ratio + b1;
CGFloat a3 = (a2 - a1) * ratio + a1;
return [UIColor colorWithRed:r3 green:g3 blue:b3 alpha:a3];
}
@end
Written by Sam Davies
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Ios
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#