Why doesn't UIVisualEffectView work in SwiftUI context menus?

Viewed 220

I have a relatively simple view, and I am trying to get UIVisualEffectView to work when used within a context menu.

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .bottomLeading) {
            Image("Flower")
                .resizable()
                .frame(width: 200, height: 200)
            
            VStack {
                Text("Line 1")
                Text("Line 2")
            }
            .frame(width: 200, height: 50)
            .background(BlurView())
        }
        .contextMenu(ContextMenu(menuItems: {
            Text("Menu Item 1")
        }))
    }
}

struct BlurView: UIViewRepresentable {
    var style: UIBlurEffect.Style = .systemMaterial
    
    func makeUIView(context: Context) -> UIVisualEffectView {
        return UIVisualEffectView(effect: UIBlurEffect(style: style))
    }
    
    func updateUIView(_ uiView: UIVisualEffectView, context: Context) {
        uiView.effect = UIBlurEffect(style: style)
    }
}

When the view loads it works great, but when the context menu is activated the whole blur just disappears.

Initial view Context menu active

Hopefully there's a workaround or I'll just have to use a completely different overlay until this is fixed.

1 Answers

This is the way how the contextMenu interferes with the underlying view.

If you don't want this behaviour, you can attach the contextMenu to an invisible overlay, so the underlying view will remain untouched:

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .bottomLeading) {
            Image("testImage")
                .resizable()
                .frame(width: 200, height: 200)

            VStack {
                Text("Line 1")
                Text("Line 2")
            }
            .frame(width: 200, height: 50)
            .background(BlurView())
        }
        .overlay(
            Color.clear
                .contentShape(Rectangle())
                .contextMenu(ContextMenu(menuItems: {
                    Text("Menu Item 1")
                }))
        )
    }
}
Related