Reputation: 16051
Is it possibly to have a gradient where there's a colour in each corner of a UIView?
Upvotes: 0
Views: 1893
Reputation: 35
Here is a working solution.
One vertical gradient bitmap mask used both as is and mirrored when drawing two color gradients.
FourTimesRGBAcomponents is the R,G,B,A components of the four corner colors UL, UR, LL and LR, i.e. ULR, ULG, ULB, ULA, URR etc.
void DrawFourGradientRect(CGContextRef Cgc,
const CGRect * Rect,
const CGFloat FourTimesRGBAcomponents[16])
{
int w;
int h;
void *MaskData;
CGColorSpaceRef GrayCS;
CGColorSpaceRef CS;
CGContextRef BC; //Bitmap context
CGFloat GrayComp[4] = {1.0, 1.0, 0.0, 1.0}; //2 * Gray+Alpha
CGGradientRef Gradient;
CGImageRef Mask;
w = Rect->size.width;
h = Rect->size.height;
//Start filling with white
CGContextSetRGBFillColor(Cgc, 1, 1, 1, 1);
CGContextFillRect(Cgc, *Rect);
//Then create vertical gradient mask bitmap, white on top, black at bottom
MaskData = malloc(w * h);
if (!MaskData)
return;
GrayCS = CGColorSpaceCreateDeviceGray();
if (!GrayCS)
{
free(MaskData);
return;
}
BC = CGBitmapContextCreate(MaskData, w, h, 8, w, GrayCS, kCGImageAlphaNone);
if (!BC)
{
CGColorSpaceRelease(GrayCS);
free(MaskData);
return;
}
Gradient = CGGradientCreateWithColorComponents(GrayCS, GrayComp, NULL, 2);
if (!Gradient)
{
CGContextRelease(BC);
CGColorSpaceRelease(GrayCS);
free(MaskData);
return;
}
CGColorSpaceRelease(GrayCS);
CGContextDrawLinearGradient(BC, Gradient, CGPointZero, CGPointMake(0, h), 0);
CGGradientRelease(Gradient);
Mask = CGBitmapContextCreateImage(BC);
CGContextRelease(BC);
free(MaskData);
if (!Mask)
return;
//Now draw first horizontal color gradient from UL to UR
CS = CGColorSpaceCreateDeviceRGB();
if (!CS)
{
CGImageRelease(Mask);
return;
}
CGContextSaveGState(Cgc);
CGContextTranslateCTM(Cgc, Rect->origin.x, Rect->origin.y);
CGContextClipToMask(Cgc, CGRectMake(0, 0, w, h), Mask);
Gradient = CGGradientCreateWithColorComponents(CS,
FourTimesRGBAcomponents, NULL, 2);
if (Gradient)
{
CGContextDrawLinearGradient(Cgc, Gradient, CGPointZero, CGPointMake(w, 0), 0);
CGGradientRelease(Gradient);
}
CGContextRestoreGState(Cgc);
//Finally draw second horizontal color gradient from LL to LR
CGContextSaveGState(Cgc);
CGContextTranslateCTM(Cgc, Rect->origin.x, Rect->origin.y + Rect->size.height);
CGContextScaleCTM(Cgc, 1, -1); //Use vertical gradient mask upside-down
CGContextClipToMask(Cgc, CGRectMake(0, 0, w, h), Mask);
Gradient = CGGradientCreateWithColorComponents(CS,
FourTimesRGBAcomponents + 8, NULL, 2);
if (Gradient)
{
CGContextDrawLinearGradient(Cgc, Gradient, CGPointZero, CGPointMake(w, 0), 0);
CGGradientRelease(Gradient);
}
CGContextRestoreGState(Cgc);
CGImageRelease(Mask);
CGColorSpaceRelease(CS);
} /* DrawFourGradientRect */
Upvotes: 1
Reputation: 2077
There's no built-in way to do this, and no simple way to do this via Quartz either. However, you can do it via Quartz by creating 4 different 2-D gradients going in different directions, and masking each one with a black-white gradient running perpendicular.
Assuming your colors are defined as: tlColor, trColor, blColor, brColor (for top-left, top-right, etc.).
You might want to try this in Acorn or Photoshop first... so it's clear what's involved before you translate it into code. Then the Quartz reference @lxt pointed you to has sections on gradients (CGGradientRef is sufficient, don't try to use shadings), and a separate section on image masks.
Upvotes: 2
Reputation: 52237
I have 2 gradients placed diagonal. With overlay-blending
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat locations2[2] = { 1.0, 0.0 };
CGFloat components[8] = {
1.0, 1.0, 0.0, 1.0 ,//Yellow
0.0, 0.0, 1.0, 1.0};//Blue
CGColorSpaceRef rgbColorspace = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGPoint point1 = CGPointMake(0, 0);
CGPoint point2 = CGPointMake(self.bounds.size.width, self.bounds.size.height);
CGContextDrawLinearGradient(currentContext, gradient, point1, point2, 0);
CGFloat components1[8] = {
0.0, 1.0, 0.0, 1.0,//Red
1.0, 0.0, 0.0, 1.0}; //Green
gradient = CGGradientCreateWithColorComponents(rgbColorspace, components1, locations2, num_locations);
CGContextSetBlendMode(currentContext, kCGBlendModeOverlay);
point1 = CGPointMake(self.bounds.size.width, 0);
point2 = CGPointMake(0, self.bounds.size.height);
CGContextDrawLinearGradient(currentContext, gradient, point1, point2, 0);
CGGradientRelease(gradient);
CGColorSpaceRelease(rgbColorspace);
}
To change the color you should have 4 UIColors as members on the view and change this fragment accordingly.
Upvotes: 1
Reputation: 31304
To be a little more helpful than Carl, the answer is 'yes', but how you implement it would depend on the tech you wanted to use. The Quartz gradient system is described here:
...but OpenGL is another possibility. It would depend on your application.
Upvotes: 0