Simple way to draw radial progress indicator with animation in iOS and Swift

This is fairly simple thing in iOS and you do not need to use any external library. I’ll use two CALayer and CABasicAnimation, so this is “cheap” way from the system resources point of view.

Start with empty project and in ViewController add three properties:

Here is two CAShapeLayer properties which representing background (constant) shape of the indicator and progress shape. percent variable will be needed for animations.

Now add progress and background shapes to the main view layer. Add the following code to the end of viewDidLoad() method:

It’s important to create shape layers once.¬†This significantly simplifies code.

Now we need to draw background and progress shapes. Add new method updateIndicator():

strokeWidth substracted from size to keep shape inside layer bounds. Also, keep in mind that it is much easier to position, rotate and scale CALayer if its size and center are the same as for the shape.

Alternative way is to set CALayer size to it’s view size and manually calculate center inside bounds.

backgroundShape can be defined in the following way:

Now we can draw progressShape:

It’s the same shape but with different color. Only one difference is that it should indicate¬†progress. There are several ways to do that and simplest is to define strokeEnd variable that accept values from 0.0 to 1.0:

Final step is to make layer and shape responsible to view frame changes, because it would not happen automatically. In this example you need to override viewWillLayoutSubviews() and add updateIndicator() call. If you implement it as a separate UIView component then override layoutSubviews() or setNeedsLayout() and add this call:

If you made everything right then you will see the same image after app start:

Perfect!

What’s about animations?

It’s just six new lines of code that set values of CABasicAnimation. However, we need to modify updateIndicator().

You probably do¬†not want¬†to animate every progress change (for example, if you set initial value), so it’s good to have animation feature optional.

Now, add animation initialization to the beginning of updateIndicator(...) method :

Here is initialization of CABasicAnimation for strokeEnd property key. Start value for animation is current value of strokeEnd, end value is percent, so animation will work for all cases. Timing function deserve separate topic for discussion, you may read more about these functions here.

Now we ready to apply animation to progressShape layer. Add this code to the end of updateIndicator() method

Finally, change call in viewWillLayoutSubviews() method to

That’s all! If you run the app then you see this:

Full code available at GitHub.

Here is how it looks like in Wasa+ app (Swedish AppStore only):

Leave a Reply

Your email address will not be published. Required fields are marked *