Как рисовать радиальные градиенты в CALayer?

Я знаю, что CAGradientLayer не поддерживает радиальный градиент в данный момент и имеет только параметр kCAGradientLayerAxial.

Мне нужно что-то вроде ниже:

enter image description here

Я рассмотрел эту проблему и обнаружил, что есть способ обойти это. Но объяснения мне не были ясны. Поэтому я хочу знать, могу ли рисовать радиальные градиенты с помощью CAGradientLayer, и если да, то как это сделать?

Ответ 1

Из того, что я понял, вам нужен слой, который рисует градиент, а CGContextDrawRadialGradient отлично работает для этой потребности. И чтобы повторить то, что вы сказали, CAGradientLayer не поддерживает радиальные градиенты, и мы ничего не можем с этим поделать, кроме ненужных swizzling, которые можно выполнить с помощью подкласса CALayer.

(примечание: код чертежа градиента был взято отсюда. Это не тот ответ, о котором идет речь.)


viewDidLoad:

GradientLayer *gradientLayer = [GradientLayer new];
gradientLayer.frame = self.view.bounds;

[self.view.layer addSublayer:gradientLayer];

Подкласс

CALayer:

- (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));
    float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ;

    CGContextDrawRadialGradient (ctx, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation);


    CGGradientRelease(gradient);
}

enter image description here

Ответ 2

Вот код Swift3, который я использую:

import UIKit

class 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))
    }
}