web-dev-qa-db-fra.com

Comment dessiner des dégradés radiaux dans un CALayer?

Je sais que CAGradientLayer ne prend pas en charge le gradient radial pour le moment et n'a que l'option kCAGradientLayerAxial.

Je veux quelque chose comme ci-dessous:

enter image description here

J'ai cherché autour de ce problème et j'ai trouvé qu'il y avait un moyen de le contourner. Mais les explications n'étaient pas claires pour moi. Je veux donc savoir si je peux dessiner des dégradés radiaux en utilisant CAGradientLayer et si oui, alors comment faire?

24
blancos

D'après ce que j'ai compris, vous avez juste besoin d'un calque qui dessine un dégradé, et CGContextDrawRadialGradient fonctionne parfaitement pour ce besoin. Et pour réitérer ce que vous avez dit, CAGradientLayer ne prend pas en charge les dégradés radiaux, et nous ne pouvons rien y faire, à part le swizzling inutile qui peut être fait proprement avec une sous-classe CALayer.

( note: le code de dessin du dégradé était tiré d'ici . Ce n'est pas de cela qu'il s'agit. )


viewDidLoad:

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

[self.view.layer addSublayer:gradientLayer];

CALayer sous-classe:

- (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);
}

enter image description here

45
Mazyod

Voici le code Swift3 que j'utilise:

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))
    }
}
20
Kirualex

Je ne sais pas quand mais maintenant vous pouvez changer CAGradientLayer's type en kCAGradientLayerRadialet ça marche.

Théoriquement, les performances de la méthode Core Animation sont meilleures que Core Graphics.

Un exemple de 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
    }
}
10
rpstw