使用UIBezierPath创建的弧形应用渐变色

32

我想创建一个以弧形的形式呈现的进度条。进度条的颜色需要根据数值变化。

我使用 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

希望能得到任何帮助!

非常感谢。

Granit

3个回答

44
你可以使用 CAGradientLayer 来实现渐变效果,再将 CAShapeLayer 用作蒙版。
例如:
- (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;


}

34
这似乎不会沿着路径绘制,相反,它似乎会绘制一个水平渐变,该渐变由路径揭示。这让你明白了吗?如何将水平渐变“弯曲”以跟随整个圆形? - Canucklesandwich
2
drawAnimation.toValue = [NSNumber numberWithFloat:10.0f]; 这句话是什么意思?为什么是10.0f? - Van Du Tran

5

这里输入图像描述

要在描边上绘制渐变,可以查看以下实现:https://dev59.com/eFkS5IYBdhLWcg3wN0O_#43668420

编辑: 简而言之,创建一个自定义的UIView类,并通过递增角度在两种颜色之间添加径向渐变,例如颜色1= 1度,颜色2 = 2度等,一直到360。然后对其应用一个圆环掩蔽。当您改变掩蔽CAShapeLayer的strokeEnd值时,也会旋转底层径向渐变。因为它们同时移动,所以看起来就像描边本身有渐变。


3
到目前为止,已经给出了很好的答案,但它们有点复杂,我认为以下逻辑应该更简单:
  1. 绘制你的形状图层的曲线/路径。
  2. 将路径自身关闭,即在相反方向上绘制相同的曲线/路径。
  3. 创建一个CAShapeLayer并将其路径设置为步骤(2)中的路径。
  4. 给(3)中的形状图层任意的描边颜色。
  5. 创建一个CAGradientLayer。
  6. 将渐变图层蒙版设置为(4)中的形状图层。
  7. 将渐变层的颜色设置为所需的数组。
  8. 将渐变层添加到原始形状图层(1)中。
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)
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接