Sheet does not appear when triggered while menu is open in SwiftUI (and thereafter)

372 Views Asked by At

I seem to be using (context) menus incorrectly in SwiftUI (or there is a serious bug):

When a menu is open and the user taps another button (⛭) in the background that is supposed to open a sheet, the menu closes automatically, but no sheet is shown.

Screenshot

What's worse: After that, I can tap the button as many times as I like and still nothing happens. Instead, the following warning is printed to the log (only the first time):

[Presentation] Attempt to present <TtGC7SwiftUI29PresentationHostingControllerVS_7AnyView: 0x105818200> on <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x10601e000> (from <TtGC7SwiftUI19UIHostingControllerGVS_15ModifiedContentVS_7AnyViewVS_12RootModifier_: 0x10601e000>) which is already presenting <_UIContextMenuActionsOnlyViewController: 0x107308e30>.

Apparently, SwiftUI presents the menu as a modal view under the hood and the settings view as well, but UIKit cannot present two modals at the same time. While I understand this problem, I'm not certain how to solve it:

  1. One way would be to disable entirely disable user-interaction on the background (i.e. on everything that's not part of the menu). But I haven't been able to find a reliable way to do that or to even detect when the menu is open. This is the best attempt of a solution I've found. Is there a better one?

  2. Another way would be to somehow first dismiss the menu before the sheet is opened. But again, I don't know how to do this. Any ideas?

This is a minimal code example to replicate the behavior:

struct ContentView: View {
    
    @State private var displaySettings: Bool = false
    
    var body: some View {
        Button {
            displaySettings = true
        } label: {
            Image(systemName: "gearshape.fill")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 50)
        }
        .toolbar {
            ToolbarItem(placement: .bottomBar) {
                Menu {
                    Button(action: {}) {
                        Label("Reset", systemImage: "arrow.counterclockwise")
                    }
                } label: {
                    Image(systemName: "ellipsis.circle")
                }
            }
        }
        .sheet(isPresented: $displaySettings) {
            Text("Settings")
        }
    }

}

⚠️ Please note that the problem only occurs on real devices. The simulator doesn't have this problem and shows the sheet as intended.

0

There are 0 best solutions below