I'm trying to make a list where each row can be clicked to show a popover, and from the popover, there is another button to open whatever url in default web browser.
Everything seems to work as is, except for the fact that on clicking open a new web browser or clicking outside the popover, I want to popover to disappear. On clicking the web browser, the top app menu disappears, but on clicking the top app menu again, it shows up again with the popover still open.
I was wondering if there's a way to unset the selector variable in my app on outside click.
This is my code:
struct AppMenu: View {
@State private var selector: String = ""
@State private var isPopoverPresented = false
private func togglePopover(_ selector: String) {
selector = ""
selector = selector
}
var body: some View {
VStack {
List {
ForEach(itemList, id: \.self) { item in
Button(action: {
togglePopover(item.Id)
}) {
Label(item.Content, systemImage: "arrow.right.circle.fill")
// Customize the color if needed
}
.popover(isPresented: Binding<Bool>(
get: { selector == item.Id },
set: { _ in }
)) {
VStack {
Button("Open in sharari") {
openURLInSafari(item.Content)
isPopoverPresented = false
}
}
}
}
}
}
}
}
}
And this component is shown in the main app scene:
MenuBarExtra("MenuStuff", systemImage: "book.fill") { AppMenu()}.menuBarExtraStyle(.window);
I tried making an overlay view that's full screen window sized, and having that fire the unset, but it seem to not be working.
Putting each item row in a subview will make the popover presentation much easier. Each view has its own state variable, you don't have to handle the
id
.Here is a possible approach:
Setting the
isPresented
attribute ofpopover
tofalse
is not neccessary in SwiftUI. It will be automatically set when focus changes.I made up your
Item
object, as it was not implemented in your example:Note that you named a property
Content
, but properties should be llamaCased and meaningfully named, so I called itcontentUrl
, which makes it clearer what's going on.