将渐变应用于CAShapeLayer

时间:2011-01-19 10:08:52

标签: iphone core-graphics quartz-graphics gradient cashapelayer

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

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

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

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

感谢。

3 个答案:

答案 0 :(得分:60)

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

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];

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

答案 1 :(得分:3)

这是一个很好的解决方案,但如果您在CAShapeLayer上创建一个您不立即拥有该视图的类别,则可能会遇到意外问题。

请参阅Setting correct frame of a newly created CAShapeLayer

底线,获取路径的边界,然后使用路径边界设置渐变蒙版的帧并根据需要进行平移。这里的好处是通过使用路径的边界而不是任何其他框架,渐变将仅适合路径边界(假设你想要的是什么)。

// Category on CAShapeLayer

CGRect pathBounds = CGPathGetBoundingBox(self.path);

CAShapeLayer *gradientMask = [CAShapeLayer layer];
gradientMask.fillColor = [[UIColor blackColor] CGColor];
gradientMask.frame = CGRectMake(0, 0, pathBounds.size.width, pathBounds.size.height);
gradientMask.path = self.path;

CAGradientLayer *gradientLayer = [CAGradientLayer layer];
gradientLayer.startPoint = CGPointMake(0.5,1.0);
gradientLayer.endPoint = CGPointMake(0.5,0.0);
gradientLayer.frame = CGRectMake(0, 0, pathBounds.size.width, pathBounds.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];
[self addSublayer:gradientLayer];

答案 2 :(得分:3)

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

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

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

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

string_p= 'seven 5 blah 6  decimal 6.5 thousands 8,999 with dollar signs $9,000 and $9,500,001.45 end ... lastly.... 8.4% now end