I have an array of CGColors that I need to display across a path. I tried doing this with a CGGradient, but I don't want the colors the blend between between values. It looks like the best solution would be to use a GGShading object, but I am having trouble figuring out exactly how they work. I'm mainly confused about what I need to have for the CGFunction input for the CGShading.
Can someone point me in the right direction on what I would need to make this CGFunction look like to to simply display an array go CGColors on a specified CGPath?
Thanks!
Perhaps a little late, so I hope this is still of use to you. I've listed the code for a simple UIView subclass that draws a circle using the shading you described. The code with comments should be self-explanatory.
@implementation CGShadingCircle
// This is the callback of our shading function.
// info: a pointer to our NSMutableArray of UIColor objects
// inData: contains a single float that gives is the current position within the gradient
// outData: we fill this with the color to display at the given position
static void CGShadingCallback(void* info, const float* inData, float* outData) {
// Our colors
NSMutableArray* colors = (NSMutableArray*)info;
// Position within the gradient, ranging from 0.0 to 1.0
CGFloat position = *inData;
// Find the color that we want to used based on the current position;
NSUInteger colorIndex = position * [colors count];
// Account for the edge case where position == 1.0
if (colorIndex >= [colors count])
colorIndex = [colors count] - 1;
// Get our desired color from the array
UIColor* color = [colors objectAtIndex:colorIndex];
// Copy the 4 color components (red, green, blue, alpha) to outData
memcpy(outData, CGColorGetComponents(color.CGColor), 4 * sizeof(CGFloat));
}
// Set up our colors and shading function
- (void)initInternal {
_colors = [[NSMutableArray alloc] init];
// Creating the colors in this way ensures that the underlying color space is UIDeviceRGBColorSpace
// and thus has 4 color components: red, green, blue, alpha
[_colors addObject:[UIColor colorWithRed:1.0f green:0.0f blue:0.0f alpha:1.0f]]; // Red
[_colors addObject:[UIColor colorWithRed:0.0f green:1.0f blue:0.0f alpha:1.0f]]; // Green
[_colors addObject:[UIColor colorWithRed:0.0f green:0.0f blue:1.0f alpha:1.0f]]; // Blue
[_colors addObject:[UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f]]; // White
[_colors addObject:[UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f]]; // Black
// Define the shading callbacks
CGFunctionCallbacks callbacks;
callbacks.version = 0; // Defaults to 0
callbacks.evaluate = CGShadingCallback; // This is our color selection function
callbacks.releaseInfo = NULL; // Not used
// As input to our function we want 1 value in the range [0.0, 1.0].
// This is our position within the 'gradient'.
size_t domainDimension = 1;
CGFloat domain[2] = {0.0f, 1.0f};
// The output of our function is 4 values, each in the range [0.0, 1.0].
// This is our selected color for the input position.
// The 4 values are the red, green, blue and alpha components.
size_t rangeDimension = 4;
CGFloat range[8] = {0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f};
// Create the shading function
_shadingFunction = CGFunctionCreate(_colors, domainDimension, domain, rangeDimension, range, &callbacks);
}
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self initInternal];
}
return self;
}
- (id)initWithCoder:(NSCoder*)decoder {
self = [super initWithCoder:decoder];
if (self) {
[self initInternal];
}
return self;
}
- (void)dealloc {
[_colors release];
CGFunctionRelease(_shadingFunction);
[super dealloc];
}
- (void)drawRect:(CGRect)rect {
CGRect b = self.bounds;
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create a simple elliptic path
CGContextAddEllipseInRect(ctx, b);
// Set the current path as the clipping path
CGContextClip(ctx);
// Create our shading using the function that was defined earlier.
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGShadingRef shading = CGShadingCreateAxial(colorspace,
CGPointMake(CGRectGetMinX(b), CGRectGetMidY(b)),
CGPointMake(CGRectGetMaxX(b), CGRectGetMidY(b)),
_shadingFunction,
true,
true);
// Draw the shading
CGContextDrawShading(ctx, shading);
// Cleanup
CGShadingRelease(shading);
CGColorSpaceRelease(colorspace);
}
@end
This gives me the following output:
I hope this helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With