Draw radial Gradient on UIView (circle) - ios

unfortunately I can't get to a solution with drawing a radial gradient in my UIView.
Look...that's how I want to draw it (this was made in PS):
But I'm currently stuck on this:
That's my code:
CGGradientRef radialGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
const CGFloat *colorComponents = CGColorGetComponents(textColor.CGColor);
CGFloat components[8] = { colorComponents[0], colorComponents[1], colorComponents[2], 1.0, // Start color
1.0, 1.0, 1.0, 1.0 }; // End color
rgbColorspace = CGColorSpaceCreateDeviceRGB();
radialGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGRect currentBounds = self.bounds;
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawRadialGradient(myContext, radialGradient, midCenter, 8.0, midCenter, 1.0, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(radialGradient);
CGColorSpaceRelease(rgbColorspace);
I hope someone can give me the right tip ;)
Enjoy the weekend,
Chris

Basically, you need to use more than 2 locations. With 2 locations you get a constant gradient between the start and end locations. Your sample image shows the start colour for most locations up to the end and a much paler end colour. Looking at the sample image you will need at least 3 locations and to change the end colour.

Related

Draw ellipse gradient in Swift [duplicate]

I need a radial gradient in the shape of an oval or ellipse and it seems like it CGContextDrawRadialGradient can only draw a perfect circle. I've been drawing to a square context then copying/drawing into a rectangular context.
Any better way to do this?
Thanks!
The only way I've found to do this is as Mark F suggested, but I think the answer needs an example to be easier to understand.
Draw an elliptical gradient in a view in iOS (and using ARC):
- (void)drawRect:(CGRect)rect {
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Create gradient
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGFloat locations[] = {0.0, 1.0};
UIColor *centerColor = [UIColor orangeColor];
UIColor *edgeColor = [UIColor purpleColor];
NSArray *colors = [NSArray arrayWithObjects:(__bridge id)centerColor.CGColor, (__bridge id)edgeColor.CGColor, nil];
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)colors, locations);
// Scaling transformation and keeping track of the inverse
CGAffineTransform scaleT = CGAffineTransformMakeScale(2, 1.0);
CGAffineTransform invScaleT = CGAffineTransformInvert(scaleT);
// Extract the Sx and Sy elements from the inverse matrix
// (See the Quartz documentation for the math behind the matrices)
CGPoint invS = CGPointMake(invScaleT.a, invScaleT.d);
// Transform center and radius of gradient with the inverse
CGPoint center = CGPointMake((self.bounds.size.width / 2) * invS.x, (self.bounds.size.height / 2) * invS.y);
CGFloat radius = (self.bounds.size.width / 2) * invS.x;
// Draw the gradient with the scale transform on the context
CGContextScaleCTM(ctx, scaleT.a, scaleT.d);
CGContextDrawRadialGradient(ctx, gradient, center, 0, center, radius, kCGGradientDrawsBeforeStartLocation);
// Reset the context
CGContextScaleCTM(ctx, invS.x, invS.y);
// Continue to draw whatever else ...
// Clean up the memory used by Quartz
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
Put in a view with a black background you get:
You can change the transform of the context to draw an ellipse (for example, apply CGContextScaleCTM(context, 2.0, 1.0) just before calling CGContextDrawRadialGradient () to draw an elliptical gradient that's twice as wide as it is high). Just remember to apply the inverse transform to your start and end points, though.

How can I draw a line with gradually change edge using CoreGraphics?

I want to accomplish a function just like a Brush. The area where finger swipes changes to trasparent with gradually changed border.
I can only change the color to crystal clear now with following codes:
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if(self.eraser) return;
CGFloat scale = self.transform.a;
if (scale < 1) scale = 1;
CGPoint p = [[touches anyObject] locationInView: self];
CGPoint q = [[touches anyObject] previousLocationInView: self];
UIImage* image;
image = self.image;
CGSize size = self.frame.size;
UIGraphicsBeginImageContext(size);
CGRect rect;
rect.origin = CGPointZero;
rect.size = size;
[image drawInRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextBeginPath(context);
CGContextSaveGState( context );
CGContextSetLineWidth(context, (10.0 / scale) + 1);
CGContextSetBlendMode(context, kCGBlendModeClear);
CGContextMoveToPoint(context, q.x, q.y);
CGContextAddLineToPoint(context, p.x, p.y);
CGContextStrokePath(context);
CGContextRestoreGState( context );
UIImage* editedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[self setBounds:rect];
[self setImage:editedImage];
}
How can I get the edge with gradually change? Thanks in advance.
You can achieve this effect by drawing a radial gradient with a variable alpha in the kCGBlendModeDestinationIn mode in each spot the user passes.
This blend mode has the effect of only applying the layer's alpha to layers below. With the variable alpha of our gradient, we can achieve this effect.
const CGFloat kBrushSize = 10.f;
CGContextSaveGState(context);
// Make a radial gradient that goes from transparent black on the inside
// to opaque back on the outside.
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0 };
CGColorSpaceRef myColorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
CGGradientRef myGradient = CGGradientCreateWithColorComponents (myColorspace, components,
locations, num_locations);
CGColorSpaceRelease(myColorspace);
// Draw the gradient at the point using kCGBlendModeDestinationIn
// This mode only applies the new layer's alpha to the lower layer.
CGContextSetBlendMode(context, kCGBlendModeDestinationIn);
CGContextDrawRadialGradient(context, myGradient, p, 0.f, p, (kBrushSize / scale) + 1, kCGGradientDrawsAfterEndLocation);
CGGradientRelease(myGradient);
CGContextRestoreGState(context);
Here is a screenshot of this code in action:
Note: Using this technique, if the user is moving his/her finger very fast, you may see a spacing effect where discrete brush dots are visible. This is a feature of some graphics software, but if this is undesirable for you, you can add code to interpolate the points between the current and last to draw more brush points, creating a more continuous stroke.
Also, you should be able to adjust the gradient color stops to achieve any kind of brush softness you like.
Source: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/dq_shadings.html

Can't get CGGradientRef to work with alpha

I am trying to apply an alpha gradient to a UIView but can't get it to work at all. My current drawRect: method looks like this -
- (void)drawRect:(CGRect)rect
{
CGContextRef currentContext = UIGraphicsGetCurrentContext();
CGGradientRef alphaGradient;
CGColorSpaceRef rgbColorSpace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 1.0, 1.0, 1.0, 1.0, // Start color
1.0, 1.0, 1.0, 0.0 }; // End color
rgbColorSpace = CGColorSpaceCreateDeviceRGB();
alphaGradient = CGGradientCreateWithColorComponents(rgbColorSpace, components, locations, num_locations);
CGRect currentBounds = self.bounds;
CGPoint bottomCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMaxY(currentBounds));
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(currentContext, alphaGradient, midCenter, bottomCenter, 0);
CGGradientRelease(alphaGradient);
CGColorSpaceRelease(rgbColorSpace);
}
I am sure there is something I am missing here. I have tried changing the RGB values to 0.0 instead of 1.0, changing the color space to gray scale, etc.
Any help pointing me in the right direction would be much appreciated. Thanks
I resolved the issue by making sure the view's background color was set to clear, then applying the view's layer as a mask on the image view.
I use CAGradient:
UIView * viewToGradient = // view to add gradient
UIColor * color1 = [UIColor lightGrayColor]; // gradient color 1
UIColor * color2 = [UIColor clearColor]; // gradient color 2
CAGradientLayer * gradientLayer = [CAGradientLayer layer];
gradientLayer.frame = viewToGradient.bounds;
gradientLayer.colors = [NSArray arrayWithObjects:(id)color1.CGColor, (id)color2.CGColor, nil];
gradientLayer.opacity = .6;
[viewToGradient.layer addSublayer:gradientLayer];

Quartz2d gradient fill an oval

I have a simple drawing routine that allows the user to draw two enclosed ovals on the screen. I want to fill the ovals with a gradient, using the inner oval to represent the "percentage" of the gradient. i.e. Th gradient will smoothly transition between the outside oval to the inside oval.
I have the interactive drawing working fine, now I just need to fill with the gradient.
Any thoughts? The docs only talk about perfectly circular gradients, not ovals.
_mike
I do not know whether it is possible oval gradient . But you can transform circle to oval. The idea is to draw a circle in transformed coordinate system.
Sample of code:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGContextScaleCTM(context, 1.0, 0.5);
CGGradientRef gradient;
CGColorSpaceRef colorspace;
CGFloat locations[2] = { 0.0, 1.0};
NSArray *colors = #[(id)[UIColor whiteColor].CGColor, (id)[UIColor blueColor].CGColor];
colorspace = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColors(colorspace, (CFArrayRef)colors, locations);
CGPoint startPoint, endPoint;
CGFloat startRadius, endRadius;
startPoint.x = 180;
startPoint.y = 180;
endPoint.x = 180;
endPoint.y = 180;
startRadius = 0;
endRadius = 100;
CGContextDrawRadialGradient (context, gradient, startPoint, startRadius, endPoint, endRadius, 0);
CGContextRestoreGState(context);
}
Result of running code:

set line width to radial gradient

I am using radial gradient to draw circle. It is working fine but now I want to set border color and border width to that. I tried it but it was not working.
Here is my code,
CGGradientRef gradient;
CGColorSpaceRef colorSpace;
CGFloat locations[] = {0.0,1.0};
CGFloat components[] = { red2,green2,blue2,1.0,red1,green1,blue1,1.0 };
colorSpace = CGColorSpaceCreateDeviceRGB();
gradient = CGGradientCreateWithColorComponents(colorSpace,components,locations,
sizeof(locations)/sizeof(CGFloat));
CGPoint start = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2 ), end = CGPointMake(self.bounds.size.width/2 , self.bounds.size.height/2);
CGFloat startRadius = 0.0, endRadius = radius;
CGContextDrawRadialGradient(contextRef,gradient,start,startRadius,end,endRadius,0);
CGContextSetLineWidth(contextRef, 5.0);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
How can I set border color and width to it?
First add QuartzCore Framework and then try this code...
[[Firstbtn layer]setBorderColor:[[UIColor blackColor]CGColor]];
[[self.Firstbtn layer]setBorderWidth:2.3];
[[self.Firstbtn layer]setCornerRadius:15];

Resources