# Half-Circle Progress Indicator on Swift. How to draw a half-circle with UIBezierPath

I want to share my experience in custom progress indicator creation. I will show how to create a custom progress indicator drawn with **UIBezierPath** like bellow:

So let’s start with the idea. We need to create 3 layers (**CALayer**) for the first indicator, and 2 layers for the second indicator. The main trick that 3 half-circles just clip each other like bellow:

This is a full class for Indicator. It has 2 modes – with the inner circle and without it, like on a first gif.

And now I will explain how it works.

Let’s discuss **getOutherGrayCircle** function. In this code, we have 3 functions for each half-circle. As they all are half-circles, then we need to understand how to draw only the first half-circle and 2 others will be similarly drawn.

```
func getOutherGrayCircle() -> CAShapeLayer {
let center = CGPoint(x: fullSize.width / 2, y: fullSize.height)
let beizerPath = UIBezierPath()
beizerPath.move(to: center)
beizerPath.addArc(withCenter: center,
radius: grayCircleSize.width / 2,
startAngle: .pi,
endAngle: 2 * .pi,
clockwise: true)
beizerPath.close()
let innerGrayCircle = CAShapeLayer()
innerGrayCircle.path = beizerPath.cgPath
innerGrayCircle.fillColor = UIColor.gray.cgColor
return innerGrayCircle
}
```

The center point of **UIBezierPath** is a center point by X and max Y on the view (center of the coordinate system on the image below). **startAngle** is always .pi and **endAngle** we need to calculate ( it depend on how many percents the indicator should show). **endAngle** has a limit in 2 * .pi

So right now we can create one half-circle. Two grays half-circles will be static, and that’s why **startAngle** and **endAngle** in **getOutherGrayCircle** and **getInnerGrayCircle** equals to .pi and 2 * .pi.

We have only 1 dynamic half-circle – **getGreenCircle**. Here we need to set **endAngle** to depend on how many percents indicator should show. For example: If we need 60% on the indicator, then**:**

endAngle=.pi + .pi * 0.6

Now we can create all 3 circles and add them to the parent layer

```
func drawShape(bounds: CGRect) {
fullSize = bounds.size
grayCircleSize = fullSize
greenCircleSize = CGSize(width: bounds.width - 6.0, height: bounds.width - 6.0)
innerGrayCircleSize = CGSize(width: greenCircleSize.width - 44.0,
height: greenCircleSize.width - 44.0)
let outerCicrcle = getOutherGrayCircle()
let greenCircle = getGreenCircle()
progressLayer = greenCircle
self.layer.addSublayer(outerCicrcle)
self.layer.addSublayer(greenCircle)
if isInnerCircleExist {
let innerGrayCircle = getInnerGrayCircle()
self.layer.addSublayer(innerGrayCircle)
}
self.layer.masksToBounds = true
}
```

For indicator without inner gray half-circle, we just don’t need to draw this layer. And that’s it.

## Resources:

Quickstart with CALayer and CABasicAnimation

How to solve the masksToBounds problem with the shadow of UIView?