将渐变颜色应用于使用UIBezierPath创建的弧

时间:2013-12-17 09:41:07

标签: ios xcode uicolor uibezierpath

我想创建一个具有弧形的进度条。进度条的颜色必须根据值进行更改。

我使用UIBezierPath bezierPathWithArcCenter创建了一个弧。我使用了以下代码:

- (void)viewDidLoad
{
    [super viewDidLoad];

    int radius = 100;

    CAShapeLayer *arc = [CAShapeLayer layer];

    arc.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:radius startAngle:60.0 endAngle:0.0 clockwise:YES].CGPath;

    arc.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                                  CGRectGetMidY(self.view.frame)-radius);

    arc.fillColor = [UIColor clearColor].CGColor;
    arc.strokeColor = [UIColor purpleColor].CGColor;
    arc.lineWidth = 15;

    [self.view.layer addSublayer:arc];

    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 5.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..
    drawAnimation.removedOnCompletion = NO;   // Remain stroked after the animation..
    drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    drawAnimation.toValue   = [NSNumber numberWithFloat:10.0f];
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [arc addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

}

结果如下:

enter image description here

我的问题是:如果值为< = 50%,如何对颜色应用渐变?我还创建了一个UIButton,它可以生成随机的CGFloat数字,以便与进度条连接起来。有没有人知道如何解决这个问题?

渐变看起来像这样:

enter image description here

任何帮助将不胜感激!

非常感谢。

花岗岩

3 个答案:

答案 0 :(得分:38)

您可以使用CAGradientLayer获取渐变效果,并使用CAShapeLayer作为蒙版。

e.g:

- (void)viewDidLoad
{
    [super viewDidLoad];

    int radius = 100;

    CAShapeLayer *arc = [CAShapeLayer layer];    
    arc.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(100, 50) radius:radius startAngle:60.0 endAngle:0.0 clockwise:YES].CGPath;

    arc.position = CGPointMake(CGRectGetMidX(self.view.frame)-radius,
                               CGRectGetMidY(self.view.frame)-radius);

    arc.fillColor = [UIColor clearColor].CGColor;
    arc.strokeColor = [UIColor purpleColor].CGColor;
    arc.lineWidth = 15; 
    CABasicAnimation *drawAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    drawAnimation.duration            = 5.0; // "animate over 10 seconds or so.."
    drawAnimation.repeatCount         = 1.0;  // Animate only once..
    drawAnimation.removedOnCompletion = NO;   // Remain stroked after the animation..
    drawAnimation.fromValue = [NSNumber numberWithFloat:0.0f];
    drawAnimation.toValue   = [NSNumber numberWithFloat:10.0f];
    drawAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    [arc addAnimation:drawAnimation forKey:@"drawCircleAnimation"];

    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame = self.view.frame;
    gradientLayer.colors = @[(__bridge id)[UIColor redColor].CGColor,(__bridge id)[UIColor blueColor].CGColor ];
    gradientLayer.startPoint = CGPointMake(0,0.5);
    gradientLayer.endPoint = CGPointMake(1,0.5);

    [self.view.layer addSublayer:gradientLayer];
     //Using arc as a mask instead of adding it as a sublayer.
     //[self.view.layer addSublayer:arc]; 
     gradientLayer.mask = arc;


}

答案 1 :(得分:1)

enter image description here

要沿笔划绘制渐变,请参阅此实现:https://stackoverflow.com/a/43668420/917802

编辑: 简而言之,创建一个自定义UIView类,通过以增加的角度在两种颜色之间迭代来为其添加径向渐变,例如, colour1 = 1度,colour2 = 2度等,一直到360.然后应用甜甜圈面膜。当您更改遮罩CAShapeLayer的strokeEnd值时,还可以旋转基础径向渐变。因为它们一起移动,看起来中风本身就有一个渐变。

答案 2 :(得分:0)

到目前为止给出的答案虽然很好,但是有点复杂,我认为以下逻辑应该更简单:

  1. 绘制形状图层的曲线/路径。
  2. 闭合路径,即绘制相同的曲线/路径,但相反。
  3. 创建一个CAShapeLayer并将其路径设置为(2)中的路径。
  4. 给(3)中的形状图层一个任意的笔触颜色。
  5. 创建一个CAGradientLayer。
  6. 在(4)中将渐变图层蒙版设置为形状图层。
  7. 将渐变图层的颜色设置为所需的阵列。
  8. 将渐变图层添加到(1)中的原始shapeLayer。
func draweCurve(fromPoint: CGPoint, toPoint: CGPoint, x: CGFloat) {
    // ------- 1 --------
    let curveLayer = CAShapeLayer()
    curveLayer.contentsScale = UIScreen.main.scale
    curveLayer.frame = CGRect(origin: .zero, size: CGSize(width: 100, height: 100))
    curveLayer.fillColor = UIColor.red.cgColor
    curveLayer.strokeColor = UIColor.blue.cgColor

    let path = UIBezierPath()
    path.move(to: fromPoint)
    let controlPoint1 = CGPoint(x: fromPoint.x + 40 * 0.45, y: fromPoint.y)
    let controlPoint2 = CGPoint(x: toPoint.x - 40 * 0.45, y: toPoint.y)
    path.addCurve(to: toPoint, controlPoint1: controlPoint1, controlPoint2: controlPoint2)
    curveLayer.path = path.cgPath

    // ------- 2 --------
    // close the path on its self
    path.addCurve(to: fromPoint, controlPoint1: controlPoint2, controlPoint2: controlPoint1)
    addGradientLayer(to: curveLayer, path: path)
}

private func addGradientLayer(to layer: CALayer, path: UIBezierPath) {
    // ------- 3 --------
    let gradientMask = CAShapeLayer()
    gradientMask.contentsScale = UIScreen.main.scale
    // ------- 4 --------
    gradientMask.strokeColor = UIColor.white.cgColor
    gradientMask.path = path.cgPath

    // ------- 5 --------
    let gradientLayer = CAGradientLayer()
    // ------- 6 --------
    gradientLayer.mask = gradientMask
    gradientLayer.frame = layer.frame
    gradientLayer.contentsScale = UIScreen.main.scale
    // ------- 7 --------
    gradientLayer.colors = [UIColor.gray.cgColor, UIColor.green.cgColor]
    // ------- 8 --------
    layer.addSublayer(gradientLayer)
}