You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中复用ActivityIndicatorView后HUD无法正常消失的问题排查

Why Your ActivityIndicatorView Stuck on Second Use (and How to Fix It)

Let's break down exactly what's going wrong here and get your HUD working reliably every time.

The Root Cause: Static Binding vs. Dynamic Binding

Your first clue is in how you're passing the loading state to ActivityIndicatorView:

ActivityIndicatorView(isShowing: .constant(serviceManager.loading)) { ... }

Using .constant(serviceManager.loading) creates a static, immutable Binding that only captures the value of serviceManager.loading at the moment the view is initialized. It doesn't listen for future changes to the @Published loading property.

Why It Worked the First Time (By Accident)

Your first use case worked because when loadSomeData() finishes, you update someData (another @Published property). Since serviceManager is an @ObservedObject, updating someData triggers a full view refresh. During this refresh, .constant(serviceManager.loading) re-evaluates and grabs the new false value, making the HUD disappear.

On the second page, you probably don't have another @Published property updating alongside loading, so the view never refreshes to pick up the new loading value. The static Binding stays stuck on true, keeping the HUD visible.

The Simple Fix: Use a Dynamic Binding

Instead of .constant, pass the dynamic Binding directly from your ObservedObject using the $ prefix. This Binding will automatically track changes to serviceManager.loading and update ActivityIndicatorView in real time.

Here's the corrected usage code:

@ObservedObject var serviceManager = ServiceManager() 
ActivityIndicatorView(isShowing: $serviceManager.loading) { // Use $serviceManager.loading here
    NavigationView { 
        ZStack { ... } 
    } 
}.onAppear(perform: self.serviceFetch) 

That's it! Now whenever serviceManager.loading changes (from true to false after your request finishes), ActivityIndicatorView will immediately reflect that change and hide the HUD.

Optional Improvements for Robustness

To make your HUD even better, consider these tweaks:

  1. Add Smooth Transitions
    Add a transition to your HUD to make show/hide animations feel more polished:

    VStack {
        Text("Loading...")
        ActivityIndicator(isAnimating: .constant(true), style: .large)
    }
    // ... existing modifiers ...
    .opacity(self.isShowing ? 1 : 0)
    .transition(.opacity) // Add this line
    
  2. Ensure Thread Safety
    Always update @Published properties on the main thread (network requests run in background threads by default):

    public func loadSomeData() {
        loading = true
        DispatchQueue.global(qos: .background).async {
            // Perform your network request here
            let fetchedData = self.fetchDataFromAPI()
            
            DispatchQueue.main.async {
                self.someData = fetchedData
                self.loading = false
            }
        }
    }
    
  3. Make the HUD Reusable
    Add parameters to customize text, indicator style, or size so you can reuse the view across your app:

    struct ActivityIndicatorView<Content>: View where Content: View { 
        @Binding var isShowing: Bool 
        var loadingText: String = "Loading..."
        var indicatorStyle: UIActivityIndicatorView.Style = .large
        var content: () -> Content 
        
        var body: some View { 
            GeometryReader { geometry in 
                ZStack(alignment: .center) { 
                    self.content() 
                        .disabled(self.isShowing) 
                        .blur(radius: self.isShowing ? 3 : 0) 
                    VStack { 
                        Text(loadingText)
                        ActivityIndicator(isAnimating: .constant(true), style: indicatorStyle) 
                    } 
                    .frame(width: geometry.size.width / 2, height: geometry.size.height / 5) 
                    .background(Color.secondary.colorInvert()) 
                    .foregroundColor(Color.primary) 
                    .cornerRadius(20) 
                    .opacity(self.isShowing ? 1 : 0)
                    .transition(.opacity)
                } 
            } 
        } 
    }
    

内容的提问来源于stack exchange,提问作者Perry Hoekstra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 09:53:09