web-dev-qa-db-ja.com

CALayerで放射状グラデーションを描画する方法は?

CAGradientLayerは現時点では放射状グラデーションをサポートしておらず、kCAGradientLayerAxialのオプションしかありません。

以下のようなものが欲しい:

enter image description here

私はこの問題を調べてみましたが、これを回避する方法があることがわかりました。しかし、説明は私には明確ではありませんでした。したがって、CAGradientLayerを使用して放射状のグラデーションを描画できるかどうかを知りたい場合は、どうすればよいでしょうか。

24
blancos

私が理解したことから、あなたはグラデーションを描くレイヤーを必要とするだけで、CGContextDrawRadialGradientはそのニーズに完全に機能します。繰り返しになりますが、CAGradientLayerは放射状グラデーションをサポートしていません。CALayerサブクラスできれいに実行できる不要なスウィズリングを除いて、それについては何もできません。

注:グラデーション描画コードは ここから引用 でした。この答えはそうではありません。


viewDidLoad

GradientLayer *gradientLayer = [[GradientLayer alloc] init];
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));
    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

私が使用する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))
    }
}
20
Kirualex

いつかはわかりませんが、CAGradientLayertypekCAGradientLayerRadialに変更できます。

理論的には、Core AnimationのパフォーマンスはCore Graphicsよりも優れています。

いくつかのサンプルコード:

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