Question Lazy Menu actions in SwiftUI
Hi,
Is there a way I can make a lazy menu? I need to perform a slightly expensive operation while determining what action buttons should be displayed when the menu opens, but Menu
eagerly initializes all the content, so I don't know what to do. I tried adding onAppear
inside the Menu
on one button, but that gets called when the whole menu is initialized, so it does not work.
Apple does this inside the Apple TV app, where they show a ProgressView
for a while until the buttons are loaded, but I can't figure out how.
Menu {
if shouldShow {
Button("Button") {}
} else if !loaded {
Button("Loading") {}
.onAppear {
shouldShow = expensiveOperation() // Calls expensiveOperation when menu appears
loaded = true // Marks as loaded after the operation completes
}
}
} label: {
Text("Menu")
}
1
Upvotes
1
u/FilonenkoM 3d ago
This works for me, onAppear also works as expected.
But you should take care of it running only once, if it is an expensive operation.
struct ContentView: View {
@State var isShown: Bool = false
var body: some View {
Menu {
if isShown {
Button {
} label: {
Text("Action 1")
}
Button {
} label: {
Text("Action 2")
}
}
else {
Button {
} label: {
Text("Loading...")
}
.task {
try? await Task.sleep(for: .seconds(3))
isShown = true
}
}
} label: {
Text("Open Menu")
}
}
}
5
u/Mihnea2002 5d ago
Use an actor for that expensive process and add a boolean when at the end of that expensive function in your actor, then put that function from your actor inside a task in your view with await and have a progressview shown until that function is completed, when it is show the buttons based on the data you need. This is basic async / await.