I have a UIBezierPath
inside my custom UIView draw(_ rect: CGRect)
function. I would like to fill the path with a gradient color. Please can anybody guide me how can I do that.
I need to fill the clip with a gradient color and then stroke the path with black color.
There are some posts in SO which does not solve the problem. For example Swift: Gradient along a bezier path (using CALayers) this post guides how to draw on a layer in UIView
but not in a UIBezierPath
.
NB: I am working on Swift-3
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)
You can do this directly in Core Graphics without using CALayer
classes. Use bezierPath.addClip()
to set the bezier path as the clipping region. Any subsequent drawing commands will be masked to that region.
I use this wrapper function in one of my projects:
func drawLinearGradient(inside path:UIBezierPath, start:CGPoint, end:CGPoint, colors:[UIColor])
{
guard let ctx = UIGraphicsGetCurrentContext() else { return }
ctx.saveGState()
path.addClip() // use the path as the clipping region
let cgColors = colors.map({ $0.cgColor })
guard let gradient = CGGradient(colorsSpace: nil, colors: cgColors as CFArray, locations: nil)
else { return }
ctx.drawLinearGradient(gradient, start: start, end: end, options: [])
ctx.restoreGState() // remove the clipping region for future draw operations
}