ProgressView in SwiftUI

ProgressView in SwiftUI
⏱ Reading Time: 5 mins

Today in this post I’m going to show you how to use the ProgressView in SwiftUI. A native view that was introduced in WWDC 2020 and makes it amazingly easy to indicate the progress of tasks that take time to complete.

There are two kind of tasks to report progress for; those for which we can determine when they are going to complete, and those with unpredictable finishing time. For that reason they exist two types of progress view respectively; the linear and the indeterminate. The first one is a bar that is getting filled according to the task’s completion amount, while the second is by default a circular activity indicator spinning around indefinitely until the task is over.

We are going to see both in this post, starting with the indeterminate type of progress view. The demonstration will not stop in the system provided views only; I will also show you how to create custom progress view styles in order to come up with custom and unique progress views.

The indeterminate progress view

The simplest way to present an indeterminate progress view is this:

The above will display the default spinner that we are all familiar with. A message can easily go along with the spinner if we simply provide it as an argument to the ProgressView:

Indeterminate progress view with message

Quite often we may want to change the default tint color. We do so by providing the desired color as an argument to a CircularProgressViewStyle instance; in turn, we use that instance as argument to the progressViewStyle view modifier:

Indeterminate progress view with tint color

To change the label’s color as well, then use the foregroundColor modifier:

Besides all the above that demonstrate the most common kind of usage of the indeterminate progress view, it’s also possible to provide and display any other SwiftUI view instead of just a text as argument. The following creates a progress view that implements a button to stop the task. That button is now the progress view’s label:

Indeterminate progress view with custom button as label

The linear progress view

In order to indicate progress with the linear progress view, we must necessarily provide it with two values:

  • The final value that indicates the task completion.
  • The current progress value towards the completion.

In its simplest form, a linear progress view can be presented like so:

progress indicates the current progress, and usually it’s a @State property:

Similarly to the indeterminate progress view, we can provide a text label here too:

Linear progress view

The default color of the progress bar can be changed with the accentColor view modifier. The label’s color can be changed with the foregroundColor modifier:

Linear progress view with accent color

Keep in mind that both the current progress and the final values are needed in order to properly present a linear progress view.

Custom progress view styles

The default appearance of the progress view can be overridden by implementing custom progress view styles. Such a style is actually a custom type, a structure, that conforms to the ProgressViewStyle protocol. The only requirement is to implement a method called makeBody(configuration:) and return either a progress view, or any other SwiftUI view customized the way we want it.

The following snippet presents a custom progress view style. All it does is to add a background color to the progress bar, change the default accent color, add some padding and rounded corners:

See that a ProgressView instance is being initialized with the configuration parameter value from the makeBody(configuration:) method, and this is what we return in the above implementation. To use it, we just create a new progress view that will be using this style with the help of the progressViewStyle view modifier:

Linear progress view with custom style and background color

I mentioned previously that the return value of the makeBody(configuration:) method can be any SwiftUI view. You can also understand that by looking at its return type; it’s some View. That means that instead of a ProgressView instance, we can return anything we want, and be as creational as we like.

Right next you can see the implementation of another custom style. The view we return this time is a ZStack with two overlapping rounded rectangles. The first one is the background of the progress view, the other indicates the current progress that is used to increase the width accordingly:

Using the above once again with the progressViewStyle modifier:

The result is this:

Linear progress view with custom style and two rounded rectangle views

A linear progress view does not have to be always horizontal. To demonstrate that, I’m presenting right next one last custom style implementation that’s a bit different from the above two:

The return value is once again a ZStack. In it we have a circular shape that its stroke is trimmed according to the current progress value; the higher the progress value, the more the circle is completed with a stroke.

The second shape is a text, “sitting” at the center of the circle and showing the progress percentage, or the “Done” value on completion.

See that in order to get the current progress we are using the fractionCompleted property from the configuration object. It’s value is in the range of 0…1, but for indeterminate progress views it becomes nil. That’s why I’m unwrapping its value before using it in the Text right above.

Using this custom style is similar to the previous cases:

And the result is this:

Linear progress view with custom style and filling circle with progress text

Summary

Presenting a progress view in SwiftUI is not difficult, especially if you want to stick to the system provided ones. You have seen the various available customization options, but if you want to create a unique progress view, then implementing custom styles is the way to go. Unleash your imagination and create amazing results. I presented a few simple styles here, but you can go as far as you want with it; it’s always up to you. In any case, I hope you found something valuable to learn here today that will help you in your projects. Thanks for reading!

If you found this post useful then please consider sharing it! Also, subscribe to my newsletter in order to be notified about everything new published here directly in your inbox, and follow me on Twitter, on YouTube, on Medium and other social media.