Apply gradient color to arc created with UIBezierPath

前端 未结 3 650
感情败类
感情败类 2020-12-12 16:00

I want to create a progress bar that has the form of an arc. The color of the progress bar has to change according to the values.

I created an arc using UIBez

相关标签:
3条回答
  • 2020-12-12 16:09

    You can use a CAGradientLayer to get the gradient effect, and use the CAShapeLayer as a mask.

    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;
    
    
    }
    
    0 讨论(0)
  • 2020-12-12 16:15

    To draw a gradient along a stroke, see this implementation: https://stackoverflow.com/a/43668420/917802

    EDIT: In short, create a custom UIView class, add a radial gradient to it by iterating between two colours at increasing angles, e.g. colour1 = 1 degree, colour2 = 2 degrees etc, all the way up to 360. Then apply a donut mask to that. As you change the strokeEnd value of the masking CAShapeLayer, you also rotate the underlying radial gradient. Because they move together it looks like the stroke itself has a gradient.

    0 讨论(0)
  • 2020-12-12 16:30

    The Answers given so far are great, but they are a bit complicated, I think the following logic should be much simpler:

    1. Draw your curve/path of your shape layer .
    2. Close the path on itself, i.e draw the same curve/path but in reverse.
    3. Create a CAShapeLayer and set its path to the path in (2).
    4. Give the shape layer in (3) an arbitrary stroke colour.
    5. Create a CAGradientLayer.
    6. Set the gradient layer mask to the shape layer in (4).
    7. Set the colours of the gradient layer to your desired array.
    8. Add the gradient layer to your original shapeLayer in (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)
    }
    
    0 讨论(0)
提交回复
热议问题