SwiftUI中复用ActivityIndicatorView后HUD无法正常消失的问题排查
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:
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 lineEnsure Thread Safety
Always update@Publishedproperties 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 } } }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

