如何在CALayer中绘制径向渐变?

bla*_*cos 26 objective-c calayer ios quartz-core

我知道CAGradientLayer目前不支持径向渐变,只能选择kCAGradientLayerAxial.

我想要下面的东西:

在此输入图像描述

我一直在寻找这个问题,并发现有一种解决方法.但这些解释对我来说并不清楚.所以我想知道我是否可以使用径向渐变CAGradientLayer,如果是,那么如何做呢?

Maz*_*yod 46

根据我的理解,你只需要一个绘制渐变的图层,并CGContextDrawRadialGradient完美地满足这种需要.并重申你所说的,CAGradientLayer不支持径向渐变,我们无法做任何事情,除了可以用CALayer子类干净地完成的不必要的调配.

(注意:渐变绘图代码是从这里获取的.这不是这个答案的内容.)


viewDidLoad:

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

[self.view.layer addSublayer:gradientLayer];
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Kir*_*lex 20

这是我使用的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))
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,这对我有用.一些注意事项: - 如果您在混合和匹配项目(Obj-C + Swift)中编码,定义CGColors数组将引发错误,因为Objective-C不允许您创建原始数据类型的数组.为了克服这个问题,您可以创建一个UIColors数组,并将它们转换为`draw`函数中的cgColor值. - 当添加到较小的子视图时,此绘制的圆形具有锯齿状边缘.我通过设置图层的"masksToBounds = true"来修复此问题,然后添加一个角半径以使包含图层的视图成为圆形,使边缘平滑. (7认同)

rps*_*stw 12

我不知道什么时候,但现在你可以改变CAGradientLayertype,以kCAGradientLayerRadial和它的作品。

从理论上讲,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
    }
}
Run Code Online (Sandbox Code Playgroud)