Do you know how much data is expected to be downloaded? If so, you could ensure the view doesn't update until the right amount of data is received and stored.
If you don't know the quantity of data, you could add a Bool and toggle it when the data loading starts, then toggle it when the data has finished loading, so the View is only refreshed when the last of the data is stored.
Another way would be to disable the UI so the user can't interact with it until the data has finished loading. The UI would update in the background, but the user wouldn't experience a slow UI as they can't interact with it anyway. You could put a partially-transparent View with a ProgressView in it at the top of a ZStack
(which would be at the bottom of the ZStack
in the code...) and hide it when you're done. I'll show you how I do it below.
There's a few ways of doing it, but I don't think there's a built-in way to achieve this. But then, I'm not a genius on SwiftData, so...
Using a blocking view:
@State private var loadingData: Bool = false
var body: some View {
ZStack {
// ... UI goes here
// ...
BlockingView()
.additional().hidden(loadingData) // Hide the view when loading data == true
}
}
struct BlockingView: View {
var body: some View {
ZStack {
Rectangle()
.fill(Color.black.opacity(0.2)) // Partially-transparent, but doesn't have to be
ProgressView(label: {
Label(title: { Text("Please Wait") }, icon: { Image(systemName: "exclamationmark.circle") })
})
.frame(width: 240, height: 100)
.background(.ultraThickMaterial)
.clipShape(RoundedRectangle(cornerRadius: 24))
.shadow(color: .black.opacity(0.3), radius: 4, x: 0, y: 0)
}
.ignoresSafeArea()
}
}
/*
This modifier is required because you can't conditionally hide a view with `.hidden()` but on the plus side, you can use this in tons of places, and add new modifiers like conditional shadows etc.
*/
public struct Additional<Content> {
public let content: Content
public init(_ content: Content) {
self.content = content
}
}
extension View {
var additional: Additional<Self> { Additional(self) }
}
extension Additional where Content: View {
@ViewBuilder func hidden(_ hide: Bool) -> some View {
if(hide) {
content.hidden()
} else {
content
}
}
}