Search code examples
swiftgradientuibezierpath

Fill circle border with gradient color using UIBezierPath


I want to fill half of a circle's border using UIBazierpath with gradient color.

Initially I tried with the full circle but it's not working, the gradient always fills the circle but not the border. Is there any way to do this?

Here's what I have so far:

let path = UIBezierPath(roundedRect: rect, cornerRadius: rect.width/2)
let shape = CAShapeLayer()
shape.path = path.cgPath
shape.lineWidth = 2.0
shape.strokeColor = UIColor.black.cgColor
self.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
shapeMask.lineWidth = 2

self.layer.addSublayer(gradient)

Edit: Added the image. I want to achieve something like this.enter image description here


Solution

  • Core graphics doesn't support an axial gradient so you need to draw this out in a more manual way.

    Here's a custom view class that draws a circle using the range of HSV colors around the circumference.

    class RadialCircleView: UIView {
        override func draw(_ rect: CGRect) {
            let thickness: CGFloat = 20
            let center = CGPoint(x: bounds.midX, y: bounds.midY)
            let radius = min(bounds.width, bounds.height) / 2 - thickness / 2
            var last: CGFloat = 0
            for a in 1...360 {
                let ang = CGFloat(a) / 180 * .pi
                let arc = UIBezierPath(arcCenter: center, radius: radius, startAngle: last, endAngle: ang, clockwise: true)
                arc.lineWidth = thickness
                last = ang
                UIColor(hue: CGFloat(a) / 360, saturation: 1, brightness: 1, alpha: 1).set()
                arc.stroke()
            }
        }
    }
    
    let radial = RadialCircleView(frame: CGRect(x: 0, y: 0, width: 200, height: 200))
    radial.backgroundColor = UIColor(red: 0.98, green: 0.92, blue: 0.84, alpha: 1) // "antique white"
    

    Copy this into a playground to experiment with the results. The colors don't exactly match your image but it may meet your needs.