SwiftUI
activity indicator
Swift programming
iOS development
UI design

How to add an activity indicator in SwiftUI

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Creating intuitive and responsive user interfaces is essential in mobile app development. One crucial aspect is providing feedback to users during operations that may take time to complete, such as network requests or complex data processing. An effective way to communicate this is through an activity indicator or spinner. In this article, we will explore how to implement an activity indicator in SwiftUI, the modern declarative UI framework introduced by Apple.

Why Use an Activity Indicator?

Activity indicators are visual cues that inform users that a process is running. They prevent user frustration by acknowledging the system's response and can improve perceived performance. In SwiftUI, we can create activity indicators by wrapping UIKit components or by leveraging SwiftUI's built-in tools.

Implementing an Activity Indicator

Using ProgressView

SwiftUI provides a ProgressView that can be used as an activity indicator. The following example demonstrates how to incorporate this into an application.

swift
1import SwiftUI
2
3struct ContentView: View {
4    @State private var isLoading = false
5
6    var body: some View {
7        VStack {
8            Button(action: {
9                self.isLoading.toggle()
10                // Simulate a network call or lengthy operation
11                DispatchQueue.global().async {
12                    sleep(2)
13                    DispatchQueue.main.async {
14                        self.isLoading.toggle()
15                    }
16                }
17            }) {
18                Text("Start Loading")
19                    .padding()
20                    .background(Color.blue)
21                    .foregroundColor(.white)
22                    .cornerRadius(10)
23            }
24
25            Spacer().frame(height: 50)
26
27            if isLoading {
28                ProgressView()
29                    .progressViewStyle(CircularProgressViewStyle())
30            }
31        }
32        .padding()
33    }
34}

Code Explanation

  • State Management: We utilize the @State property wrapper for tracking the loading state. When the button is pressed, isLoading toggles to true, simulating the start of a network call.
  • Button Action: The button triggers a simulated operation using DispatchQueue. After a delay of 2 seconds, it toggles isLoading back to false.
  • Conditional Loading: The ProgressView appears only when isLoading is true, creating a seamless indication of activity.

Customizing with UIKit

SwiftUI doesn’t currently allow the full customization of ProgressView beyond style and color. To achieve more customizations, you can wrap UIKit’s UIActivityIndicatorView.

swift
1import SwiftUI
2import UIKit
3
4struct ActivityIndicator: UIViewRepresentable {
5    typealias UIViewType = UIActivityIndicatorView
6
7    func makeUIView(context: Context) -> UIActivityIndicatorView {
8        let activityIndicator = UIActivityIndicatorView(style: .large)
9        activityIndicator.color = .gray
10        return activityIndicator
11    }
12
13    func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
14        uiView.startAnimating()
15    }
16}
17
18struct ContentViewWithUIKitSpinner: View {
19    @State private var isLoading = false
20
21    var body: some View {
22        VStack {
23            Button(action: {
24                isLoading.toggle()
25                DispatchQueue.global().async {
26                    sleep(3)
27                    DispatchQueue.main.async {
28                        isLoading.toggle()
29                    }
30                }
31            }) {
32                Text("Start Loading")
33                    .padding()
34                    .background(Color.blue)
35                    .foregroundColor(.white)
36                    .cornerRadius(10)
37            }
38
39            Spacer().frame(height: 50)
40
41            if isLoading {
42                ActivityIndicator()
43            }
44        }
45        .padding()
46    }
47}

UIKit Spinner Explanation

  • UIViewRepresentable: Use UIViewRepresentable to bridge UIKit views into SwiftUI.
  • makeUIView & updateUIView: Create and update the UIActivityIndicatorView within these functions.
  • Customization: Modify properties like style and color to fit your application's design.

Summary Table

Below is a summary of key approaches and their respective advantages.

ApproachDescriptionAdvantages
Using ProgressViewBuilt-in SwiftUI componentEasy to implement, requires minimal code
UIKit SpinnerCustom activity indicator using UIViewRepresentableExpanded customization options
Conditional DisplayUse @State to control visibilityDynamic feedback based on app state

Additional Enhancements

  • Animations: Consider adding subtle animations or transitions to improve the appearance when activity indicators appear or disappear.
  • Dynamic Messages: Pair activity indicators with descriptive text to provide more context on the operation being performed.
  • Testing: Test performance and smoothness of transitions under different network conditions to ensure a consistent user experience.

Incorporating an activity indicator in SwiftUI enhances user experience by providing immediate feedback during asynchronous tasks. Whether using built-in components or integrating UIKit, you can effectively convey system activity and improve the overall feel of your application.


Course illustration
Course illustration

All Rights Reserved.