Implementation and Evolution of Full-Screen Activity Indicators in SwiftUI

Nov 30, 2025 · Programming · 13 views · 7.8

Keywords: SwiftUI | Activity Indicator | ProgressView

Abstract: This article provides an in-depth exploration of various methods for implementing full-screen activity indicators in SwiftUI, with a focus on the ProgressView introduced in iOS 14 and alternative solutions for earlier versions. Through detailed code examples and architectural analysis, it explains how to create activity indicators that conform to Apple's design standards and compares the advantages and disadvantages of different implementation approaches. The article also covers the implementation principles of custom animated indicators, offering comprehensive technical guidance for developers.

The Evolution of Activity Indicators in SwiftUI

With the continuous development of the SwiftUI framework, the implementation methods for activity indicators have undergone significant evolution. Prior to iOS 14, developers needed to rely on UIKit components to achieve native activity indicator effects, while the introduction of ProgressView in iOS 14 provided a more native SwiftUI solution.

Modern Solutions for iOS 14 and Later

In Xcode 12 and later versions, SwiftUI introduced the ProgressView component, which is the preferred solution for implementing activity indicators. This component defaults to the CircularProgressViewStyle, perfectly replicating the standard loading animation of the iOS system.

struct ModernActivityIndicator: View {
    var body: some View {
        VStack {
            ProgressView()
                .progressViewStyle(CircularProgressViewStyle())
        }
    }
}

The advantage of this approach is that it fully adheres to SwiftUI's design philosophy, eliminating the need for UIKit dependencies while maintaining high consistency with the system UI. Developers can customize the indicator's color using the tint modifier and adjust its size with scaleEffect, enabling flexible visual customization.

Bridging Solutions for Earlier Versions

For projects that need to support iOS 13, the UIActivityIndicatorView from UIKit can be wrapped into a SwiftUI component using the UIViewRepresentable protocol. This bridging technique allows developers to reuse mature UIKit components within the SwiftUI environment.

struct LegacyActivityIndicator: UIViewRepresentable {
    
    @Binding var isAnimating: Bool
    let style: UIActivityIndicatorView.Style
    
    func makeUIView(context: Context) -> UIActivityIndicatorView {
        let indicator = UIActivityIndicatorView(style: style)
        return indicator
    }
    
    func updateUIView(_ uiView: UIActivityIndicatorView, context: Context) {
        if isAnimating {
            uiView.startAnimating()
        } else {
            uiView.stopAnimating()
        }
    }
}

This implementation ensures behavioral consistency with native system components while providing full configuration options, including style selection, color settings, and all other features supported by UIKit.

Architectural Design of Full-Screen Loading Views

In practical applications, activity indicators typically need to be displayed as overlays on top of full-screen content. Using the ZStack layout container, professional full-screen loading interfaces can be constructed.

struct FullScreenLoadingView<Content: View>: View {
    
    @Binding var isShowing: Bool
    let content: () -> Content
    
    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .center) {
                
                content()
                    .disabled(isShowing)
                    .blur(radius: isShowing ? 3 : 0)
                
                if isShowing {
                    VStack(spacing: 20) {
                        Text("Loading...")
                            .font(.headline)
                        LegacyActivityIndicator(isAnimating: .constant(true), style: .large)
                    }
                    .frame(width: geometry.size.width * 0.6,
                           height: geometry.size.height * 0.2)
                    .background(Color(.systemBackground))
                    .foregroundColor(Color.primary)
                    .cornerRadius(16)
                    .shadow(radius: 10)
                }
            }
        }
    }
}

This design not only provides visual loading feedback but also ensures a good user experience by disabling underlying interactions and adding blur effects.

Implementation of Custom Animated Indicators

Beyond using system-provided components, developers can create fully custom activity indicators. By combining basic SwiftUI graphics and animation effects, unique loading animations can be achieved.

struct CustomSpinner: View {
    
    @State private var rotationAngle: Double = 0
    
    var body: some View {
        Circle()
            .trim(from: 0.2, to: 0.8)
            .stroke(Color.blue, lineWidth: 4)
            .frame(width: 40, height: 40)
            .rotationEffect(Angle(degrees: rotationAngle))
            .onAppear {
                withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) {
                    rotationAngle = 360
                }
            }
    }
}

The advantage of custom implementations is complete control over animation details and visual effects, but it requires developers to have a deep understanding of SwiftUI's animation system.

Performance Optimization and Best Practices

When implementing activity indicators, performance considerations are crucial. Unnecessary view redraws should be avoided, and animation states should be managed properly. For long-running operations, it's recommended to use DispatchQueue for asynchronous processing to ensure UI fluidity.

struct OptimizedLoadingView: View {
    
    @State private var isLoading = false
    
    var body: some View {
        VStack {
            if isLoading {
                ProgressView()
                    .scaleEffect(1.5)
            } else {
                Text("Content Loaded")
            }
        }
        .onAppear {
            isLoading = true
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                isLoading = false
            }
        }
    }
}

Through state management and appropriate asynchronous scheduling, activity indicators can be accurately displayed when needed and promptly hidden when tasks are completed.

Conclusion and Future Outlook

SwiftUI offers multiple technical paths for implementing activity indicators, ranging from simple ProgressView to complex custom animations. Developers should choose the most appropriate solution based on project requirements, target iOS versions, and design specifications. As SwiftUI continues to evolve, more native loading state management tools are expected to emerge, further simplifying the development process.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.