Drawing A Circle With Gradient Stroke
The basic idea is to use your path as a clipping path, then draw the gradient.
let c = UIGraphicsGetCurrentContext()!
let clipPath: CGPath = UIBezierPath(ovalIn: converted_rect).cgPath
c.saveGState()
c.setLineWidth(9.0)
c.addPath(clipPath)
c.replacePathWithStrokedPath()
c.clip()
// Draw gradient
let colors = [UIColor.blue.cgColor, UIColor.red.cgColor]
let offsets = [ CGFloat(0.0), CGFloat(1.0) ]
let grad = CGGradient(colorsSpace: CGColorSpaceCreateDeviceRGB(), colors: colors as CFArray, locations: offsets)
let start = converted_rect.origin
let end = CGPoint(x: converted_rect.maxX, y: converted_rect.maxY)
c.drawLinearGradient(grad!, start: start, end: end, options: [])
c.restoreGState()
let result = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
Setup a CGGradient
first with the desired colors. Then for a linear gradient you use drawLinearGradient
. For a radial gradient, use drawRadialGradient
.
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;
}
How to fill a bezier path with gradient color
To answer this question of yours,
I have a UIBezierPath inside my custom UIView draw(_ rect: CGRect)
function. I would like to fill the path with a gradient color.
Lets say you have an oval path,
let path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 100, height: 100))
To create a gradient,
let gradient = CAGradientLayer()
gradient.frame = path.bounds
gradient.colors = [UIColor.magenta.cgColor, UIColor.cyan.cgColor]
We need a mask layer for gradient,
let shapeMask = CAShapeLayer()
shapeMask.path = path.cgPath
Now set this shapeLayer
as mask
of gradient
layer and add it to view
's layer as subLayer
gradient.mask = shapeMask
yourCustomView.layer.addSublayer(gradient)
Update
Create a base layer with stroke and add before creating gradient layer.
let shape = CAShapeLayer()
shape.path = path.cgPath
shape.lineWidth = 2.0
shape.strokeColor = UIColor.black.cgColor
self.view.layer.addSublayer(shape)
let gradient = CAGradientLayer()
gradient.frame = path.bounds
gradient.colors = [UIColor.magenta.cgColor, UIColor.cyan.cgColor]
let shapeMask = CAShapeLayer()
shapeMask.path = path.cgPath
gradient.mask = shapeMask
self.view.layer.addSublayer(gradient)
SwiftUI Circular Stroke Gradient
for 1) you could try:
private let gradient = AngularGradient(
gradient: Gradient(colors: [Color.blue, .white]),
center: .center,
startAngle: .degrees(270),
endAngle: .degrees(0))
for 2) you could try something like this:
public var body: some View {
ZStack {
Circle().stroke(Color.white, lineWidth: 46)
Circle()
.trim(from: 0, to: CGFloat(0.8))
.stroke(gradient, style: StrokeStyle(lineWidth: 46, lineCap: .round))
.overlay(
Circle().trim(from: 0, to: CGFloat(0.8))
.rotation(Angle.degrees(-4))
.stroke(gradient, style: StrokeStyle(lineWidth: 46, lineCap: .butt)))
}.padding(60)
}
Related Topics
How to Catch All iOS Push Notifications with Different User Actions Including Tap on App Icon
When Exactly Do Implicit Animations Take Place in iOS
How to Really Remove Copy from Uimenucontroller
Swift - How to Record Video in Mp4 Format with Uiimagepickercontroller
Change Uiimageview Size to Match Image with Autolayout
Two iOS Apps Using the Same Facebook App Id - Is It Possible
How to Get the iOS Device CPU Architecture in Runtime
How to Play Video Stream with Mpmovieplayercontroller in iOS
Play Mp3 Files with iPhone Sdk
Opengl Es 2.0 to Video on iPad/Iphone
iOS Uiimage Storage Formats, Memory Usage and Encoding/Decoding
How to Know Users Click Fast Forward and Fast Rewind Buttons on the Playback Controls in Iphone
Why Can't I Call the Default Super.Init() on Uiviewcontroller in Swift