How to draw radial gradients in a CALayer? How to draw radial gradients in a CALayer? ios ios

# How to draw radial gradients in a CALayer?

From what I understood, you just need a layer that draws a gradient, and `CGContextDrawRadialGradient` works perfectly for that need. And to reiterate on what you said, `CAGradientLayer` doesn't support radial gradients, and nothing we can do about that, except unnecessary swizzling that can be done cleanly with a `CALayer` subclass.

(note: the gradient drawing code was taken from here. It isn't what this answer is about.)

`viewDidLoad`:

``GradientLayer *gradientLayer = [[GradientLayer alloc] init];gradientLayer.frame = self.view.bounds;[self.view.layer addSublayer:gradientLayer];``

`CALayer` subclass:

``- (instancetype)init{    self = [super init];    if (self) {        [self setNeedsDisplay];    }    return self;}- (void)drawInContext:(CGContextRef)ctx{    size_t gradLocationsNum = 2;    CGFloat gradLocations[2] = {0.0f, 1.0f};    CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.5f};    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);    CGColorSpaceRelease(colorSpace);    CGPoint gradCenter= CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));    CGFloat gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ;    CGContextDrawRadialGradient (ctx, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);    CGGradientRelease(gradient);}``

Here is the Swift3 code I use :

``import UIKitclass RadialGradientLayer: CALayer {    required override init() {        super.init()        needsDisplayOnBoundsChange = true    }    required init?(coder aDecoder: NSCoder) {        super.init(coder: aDecoder)    }    required override init(layer: Any) {        super.init(layer: layer)    }    public var colors = [UIColor.red.cgColor, UIColor.blue.cgColor]    override func draw(in ctx: CGContext) {        ctx.saveGState()        let colorSpace = CGColorSpaceCreateDeviceRGB()        var locations = [CGFloat]()        for i in 0...colors.count-1 {            locations.append(CGFloat(i) / CGFloat(colors.count))        }        let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations)        let center = CGPoint(x: bounds.width / 2.0, y: bounds.height / 2.0)        let radius = min(bounds.width / 2.0, bounds.height / 2.0)        ctx.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: radius, options: CGGradientDrawingOptions(rawValue: 0))    }}``

I don't know when but now you can change `CAGradientLayer` 's `type` to `kCAGradientLayerRadial`and it works.

Theoretically the performance of the Core Animation way is better than Core Graphics.

Some example code:

``class View : UIView {    let gradientLayer = CAGradientLayer()    override init(frame: CGRect) {        super.init(frame: frame)        gradientLayer.startPoint = CGPoint(x: 0.5, y: 0.5)        gradientLayer.endPoint = CGPoint(x: 1, y: 1)        gradientLayer.locations = [            NSNumber(value: 0.6),            NSNumber(value: 0.8)        ]        gradientLayer.type = .radial        gradientLayer.colors = [            UIColor.green.cgColor,            UIColor.purple.cgColor,            UIColor.orange.cgColor,            UIColor.red.cgColor        ]        self.layer.addSublayer(gradientLayer)    }    required init?(coder aDecoder: NSCoder) {        super.init(coder: aDecoder)    }    override func layoutSublayers(of layer: CALayer) {        assert(layer === self.layer)        gradientLayer.frame = layer.bounds    }}``