【问题标题】:Applying a Gradient to CAShapeLayer对 CAShapeLayer 应用渐变
【发布时间】:2011-06-11 15:53:54
【问题描述】:

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

与 CAShapeLayer 相关的一切(阴影、形状、笔触颜色、可动画的形状路径)都很棒。

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

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

谢谢。

【问题讨论】:

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


【解决方案1】:

非常感谢@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

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

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

【讨论】:

    【解决方案2】:

    这是一个很好的解决方案,但是如果您在 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];
    

    【讨论】:

      【解决方案3】:

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

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

      如果您还想使用阴影,则必须在渐变层下方放置一个“复制”形状层,循环使用相同的路径参考。

      【讨论】:

      • 这是一个了不起的答案。对于那些不知道这一点的人(就像我一样),我想补充一点,您可以将蒙版、渐变、阴影和您可能需要的任何其他层添加到容器层 (CALayer container = [CALayer layer]),然后只需要管理如果您需要为其位置设置动画,则该容器层。
      • 很好的答案!谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-08
      相关资源
      最近更新 更多