I am currently struggling to resolve a SwiftUI issue:
In a very abstract way, this is how the code of my application looks like (not the actual code to simply things for the discussion here):
struct SwiftUIView: View {
@State private var toggle: Bool = true
var body: some View {
VStack {
Spacer()
if toggle {
Text("on")
} else {
Text("off")
}
Spacer()
Rectangle()
.frame(height: 200)
.onTapGesture { toggle.toggle() }
Spacer()
Menu("Actions") {
Button("Duplicate", action: { toggle.toggle() })
Button("Rename", action: { toggle.toggle() })
Button("Delete", action: { toggle.toggle() })
}
Spacer()
}
}
}
So what's the essence here?
Now, I am facing the following issue:
When opening the menu by tapping on "Actions" the menu opens up - so far so good. However, when I now decide that I don't want to trigger any of the actions contained in the menu, and tap somewhere on the background to close it, it can happen that I tap on the rectangle in the background. If I do so, the tap on the rectangle directly triggers the action defined in onTapGesture.
However, the desired behavior would be that when the menu is open, I can tap anywhere outside the menu to close it without triggering any other element.
Any idea how I could achieve this? Thanks!
(Let me know in the comments if further clarification is needed.)
You can implement an .overlay
which is tappable and appears when you tap on the menu.
Make it cover the whole screen, it gets ignored by the Menu.
When tapping on the menu icon you can set a propertie to true.
When tapping on the overlay or a menu item, set it back to false.
You can use place it in your root view and use a viewmodel with @Environment to access it from everywhere.
The only downside is, that you need to place isMenuOpen = false
in every menu button.
Apple is using the unexpected behaviour itself, a.ex in the Wether app. However, I still think it's a bug and filed a report. (FB10033181)
@State var isMenuOpen: Bool = false
var body: some View {
NavigationView{
NavigationLink{
ChildView()
} label: {
Text("Some NavigationLink")
.padding()
}
.toolbar{
ToolbarItem(placement: .navigationBarTrailing){
Menu{
Button{
isMenuOpen = false
} label: {
Text("Some Action")
}
} label: {
Image(systemName: "ellipsis.circle")
}
.onTapGesture {
isMenuOpen = true
}
}
}
}
.overlay{
if isMenuOpen {
Color.white.opacity(0.001)
.ignoresSafeArea()
.frame(maxWidth: .infinity, maxHeight: .infinity)
.onTapGesture {
isMenuOpen = false
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With