将渐变应用于CAShapeLayer

use*_*126 32 iphone gradient core-graphics quartz-graphics cashapelayer

有没有人有任何将渐变应用于CAShapeLayer的经验?CAShapeLayer是一个很棒的图层类,但它似乎只支持实心填充着色,而我希望它有一个渐变填充(实际上是一个可动画的渐变).

与CAShapeLayer(阴影,形状,笔触颜色,动画形状路径)相关的所有其他内容都非常棒.

我已经尝试将CAGradientLayer放在CAShapeLayer中,或者确实将CAShapeLayer设置为GradientLayer的掩码并将两者都添加到容器层,但这些都没有正确的结果.

我应该继承CAShapeLayer,还是有更好的前进方向?

谢谢.

Pal*_*ndo 61

您可以使用形状的路径来创建遮罩层并将其应用于渐变层,如下所示:

UIView *v = [[UIView alloc] initWithFrame:self.window.frame];

CAShapeLayer *gradientMask = [CAShapeLayer layer];   
gradientMask.fillColor = [[UIColor clearColor] CGColor];
gradientMask.strokeColor = [[UIColor blackColor] CGColor];
gradientMask.lineWidth = 4;
gradientMask.frame = CGRectMake(0, 0, v.bounds.size.width, v.bounds.size.height);

CGMutablePathRef t = CGPathCreateMutable();    
CGPathMoveToPoint(t, NULL, 0, 0);
CGPathAddLineToPoint(t, NULL, v.bounds.size.width, v.bounds.size.height);

gradientMask.path = t;


CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(0, 0, v.bounds.size.width, v.bounds.size.height);
NSMutableArray *colors = [NSMutableArray array];
for (int i = 0; i < 10; i++) {
    [colors addObject:(id)[[UIColor colorWithHue:(0.1 * i) saturation:1 brightness:.8 alpha:1] CGColor]];
}
gradientLayer.colors = colors;

[gradientLayer setMask:gradientMask];
[v.layer addSublayer:gradientLayer];
Run Code Online (Sandbox Code Playgroud)

如果您还想使用阴影,则必须在渐变图层下放置形状图层的"复制",从而回收相同的路径参考.

  • 这是一个惊人的答案.对于那些没有意识到这一点的人(就像我一样),我想补充说你可以将面膜,渐变,阴影和任何其他层添加到Container层(`CALayer container = [CALayer layer]`)然后,如果您需要为其位置设置动画,则只需管理该容器图层. (3认同)

Tun*_*Fam 6

非常感谢@Palimondo的出色回答!

如果有人正在寻找Swift 4 + 填充此解决方案的动画代码:

    let myView = UIView(frame: .init(x: 0, y: 0, width: 200, height: 150))
    view.addSubview(myView)
    myView.center = view.center

    // Start and finish point
    let startPoint = CGPoint(x: myView.bounds.minX, y: myView.bounds.midY)
    let finishPoint = CGPoint(x: myView.bounds.maxX, y: myView.bounds.midY)

    // Path
    let path = UIBezierPath()
    path.move(to: startPoint)
    path.addLine(to: finishPoint)

    // Gradient Mask
    let gradientMask = CAShapeLayer()
    let lineHeight = myView.frame.height
    gradientMask.fillColor = UIColor.clear.cgColor
    gradientMask.strokeColor = UIColor.black.cgColor
    gradientMask.lineWidth = lineHeight
    gradientMask.frame = myView.bounds
    gradientMask.path = path.cgPath

    // Gradient Layer
    let gradientLayer = CAGradientLayer()
    gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
    gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)

    // make sure to use .cgColor
    gradientLayer.colors = [UIColor.red.cgColor, UIColor.green.cgColor]
    gradientLayer.frame = myView.bounds
    gradientLayer.mask = gradientMask

    myView.layer.addSublayer(gradientLayer)

    // Corner radius
    myView.layer.cornerRadius = 10
    myView.clipsToBounds = true
Run Code Online (Sandbox Code Playgroud)

额外的。如果您还需要“填充动画”,请添加以下行:

    // Filling animation
    let animation = CABasicAnimation(keyPath: "strokeEnd")
    animation.fromValue = 0
    animation.duration = 10
    gradientMask.add(animation, forKey: "LineAnimation")
Run Code Online (Sandbox Code Playgroud)