Apply gradient color to arc created with UIBezierPath
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;
}
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.
The Answers given so far are great, but they are a bit complicated, I think the following logic should be much simpler:
- Draw your curve/path of your shape layer .
- Close the path on itself, i.e draw the same curve/path but in reverse.
- Create a CAShapeLayer and set its path to the path in (2).
- Give the shape layer in (3) an arbitrary stroke colour.
- Create a CAGradientLayer.
- Set the gradient layer mask to the shape layer in (4).
- Set the colours of the gradient layer to your desired array.
- 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)
}