Rounded Progress Bar in SWIFT

Leela Prasad
3 min readMar 17, 2018

--

Hi, Every one! Being your fellow IOS Developer, Here I come with my second story on How to make Rounded Progress Bar. In IOS, We have Status bar, but we can not make it rounded. Let’s dive into code, How to make it ourselves.

First, We draw this by using CAShapeLayer() class objects, on a uiview sub class, Then we present that View, on our screen or window.

  1. Take an IBDesginable class, which is sub class of UIView.

@IBDesignable

class RoundProgressBar: UIView {

}

2. Properties We need For This Component.

we draw backLayaer, which is in light color and then we make another layer on top of it with another color, to mark the progress with current value. So, It has minimum, maximum and current values to represent it’s appearance. So, Properties For 2 layers, background & foreground, min,max and current Values, and some IBInspectables for rendering the visuals on Interface Builder.

private var bgLayer = CAShapeLayer()

private var fgLayer = CAShapeLayer()

var minValue: Double = 0

var maxValue: Double = 1.0

var currentValue: Double = 0 {

didSet{

fgLayer.strokeEnd = currentValue > 0.01 ? CGFloat(currentValue) : 0.01

}

}

IBInspectables for Colors and Bar Width

@IBInspectable var progressBarWidth: CGFloat = 20.0 {

didSet{

configureView()

}

}

@IBInspectable var progressBarTintColor: UIColor = UIColor.lightGray {

didSet{

configureView()

}

}

@IBInspectable var progressBarProgressColor: UIColor = UIColor.clear {

didSet{

configureView()

}

}

Initialisations for this class

override init(frame: CGRect) {

super.init(frame: frame)

configureView()

}

required init?(coder aDecoder: NSCoder) {

super.init(coder: aDecoder)

configureView()

}

On change Of Colors and current values, We calling a method “configureView()” to update the progressbar. In this method, background and foreground CAShapeLayer objects, specified their Width, FillColor, Which fills he color on entire drawing area, but here we don’t want full filled circle, so give nil. the draw object starts from 0, default. so for background object, we have given 1, to draw that background layer fully. but foreground layer, we set that end point to 0.01, to make it visible a tiny bit of filled color, for good appearance. Then we added those layers to view’s layer, to make them visible. Finally we set the colors, which are defined previously to these layers, with layer.strokeColor.

func configureView() {

bgLayer.lineWidth = progressBarWidth

bgLayer.fillColor = nil

bgLayer.strokeEnd = CGFloat(maxValue)

layer.addSublayer(bgLayer)

fgLayer.lineWidth = progressBarWidth

fgLayer.fillColor = nil

fgLayer.strokeEnd = 0.01

layer.addSublayer(fgLayer)

bgLayer.strokeColor = progressBarTintColor.cgColor

fgLayer.strokeColor = progressBarProgressColor.cgColor

}

Drawing Layers with the help of “UIBezierPath” object.

We need to draw our shapes, as we need rounded circles, with radius difference as given barwidth value, with same centers. So, we use UIBezierPath() object, to create drwing path on CGLayer. here I have given 35% of taken view’s Width. you can customize that more by passing a parameter or As your requirement.

func setupCAShapeLayers(shapeLayer: CAShapeLayer, startAngle: CGFloat, endAngle: CGFloat) {

shapeLayer.frame = self.bounds

let center = CGPoint.init(x: self.frame.width/2, y: self.frame.height/2)

let radius = (self.bounds.width * 0.35)

let path = UIBezierPath.init(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)

shapeLayer.path = path.cgPath

}

Finally, call the above method by Overriding, layoutSubviews for rendering the positions correctly on change of orientation changes. It is called for multiple times for rendering UIcomponents on screen. So, We call ConfigureView() Method in initialisation, but this draw method, on LayoutSubviews() Method.

override func layoutSubviews() {

super.layoutSubviews()

configureView()

setupCAShapeLayers(shapeLayer: bgLayer, startAngle: 0, endAngle: CGFloat(Double.pi*2))

setupCAShapeLayers(shapeLayer: fgLayer, startAngle: CGFloat(Double.pi/2), endAngle: CGFloat(Double.pi*2) + CGFloat(Double.pi/2))

}

Now, Take Any uiview() Object on Interface builder or programatically, With the class we have written. “RoundProgressBar”. Through Interface Builder, Assign this class to that view. Programatically, create the View like Following.

let roundedProgress = RoundProgress.init(frame: CGRect.init(x: 75, y: 25, width: 200, height: 200))

roundedProgress.backgroundColor = .blue

roundedProgress.progressBarWidth = 5

roundedProgress.progressBarTintColor = .gray

roundedProgress.progressBarProgressColor = .yellow

view.addSubview(roundedProgress)

That is all. Hope You enjoy my story. Have a good one!

--

--