Pinch gesture not recognized on MTKView when attaching it to a RealityView using a ViewAttachmentComponent in a immersive space

Hello!

We are seeing a problem with a SwiftUI view that wraps an MTKView and that MTKView uses gesture recognizers from UIKit. One of those gestures we are using is UIPinchGestureRecognizer. And that gesture isn’t recognized at all when the SwiftUI view is attached to a RealityView using the ViewAttachmentComponent AND the RealityView is being shown in an ImmersiveSpace. If the SwiftUI view is attached to the RealityView using the init that has an attachment closure then pinching works fine there. So this definitely seems like a bug.

Here is some code to help you reproduce the problem. Run this on a Vision Pro device.

A simple red square will be rendered and if a single tap or pinch gesture is recognized on the red square, it will print to the console.

App Code:

import SwiftUI

@main
struct VisionPinchProblemsApp: App {
    var body: some Scene {
        WindowGroup {
            MenuView()
        }
        
        ImmersiveSpace(id: "RedSquare") {
            RedSquareView()
        }
    }
}

View code:

import MetalKit
import RealityKit
import SwiftUI
import UIKit

struct MenuView: View {
    @Environment(\.openImmersiveSpace)
    private var openImmersiveSpace
    @Environment(\.dismissImmersiveSpace)
    private var dismissImmersiveSpace
    
    @State private var showImmersiveSpace = false
    @State private var immersiveSpaceIsOpen = false
    
    var body: some View {
        Form {
            Toggle("Show red square", isOn: $showImmersiveSpace)
                .task(id: showImmersiveSpace) {
                    if showImmersiveSpace {
                        await openImmersiveSpace(id: "RedSquare")
                        immersiveSpaceIsOpen = true
                    } else {
                        if immersiveSpaceIsOpen {
                            await dismissImmersiveSpace()
                            immersiveSpaceIsOpen = false
                        }
                    }
                }
        }
        .onDisappear {
            // Attempt to close the immersive space on the way out.
            Task {
                if immersiveSpaceIsOpen {
                    await dismissImmersiveSpace()
                }
            }
        }
    }
}

struct RedSquareView: View {
    let metalViewAttachmentID = "metalID"
    
    var body: some View {
        // Adds SwiftUI view using attachments closure.
        // Pinching and single taps are recognized here!
        
//        RealityView { content, attachments in
//            if let metalViewEntity = attachments.entity(for: metalViewAttachmentID) {
//                metalViewEntity.position = [0, 1, -1.25]
//                content.add(metalViewEntity)
//            }
//        } placeholder: {
//            ProgressView()
//        } attachments: {
//            Attachment(id: metalViewAttachmentID) {
//                MetalView()
//            }
//        }
        
        // Add SwiftUI view using ViewAttachmentComponent.
        
        // Pinching is not recognized here!
        // Single tapping is recognized !
        
        // Why doesn't the red square show up in the Vision Pro simulator?
        
        RealityView { content in
            let metalViewEntity = Entity()
            
            let metalView = MetalView()
                .frame(width: 500, height: 500)
            
            let component = ViewAttachmentComponent(rootView: metalView)
            metalViewEntity.components.set(component)
            
            metalViewEntity.position = [0, 1, -1.25]
            
            content.add(metalViewEntity)
        } placeholder: {
            ProgressView()
        }
    }
}

struct MetalView: UIViewRepresentable {
    var device: MTLDevice?
    
    init() {
        self.device = MTLCreateSystemDefaultDevice()
    }
    
    func makeUIView(context: Context) -> MTKView {
        let mtkView = MTKView()
        mtkView.device = device
        mtkView.clearColor = MTLClearColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
        mtkView.delegate = context.coordinator
        
        let pinchGesture = UIPinchGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handlePinch(_:)))
        mtkView.addGestureRecognizer(pinchGesture)
        
        let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(context.coordinator.handleTap(_:)))
        mtkView.addGestureRecognizer(tapGesture)
        
        return mtkView
    }
    
    func updateUIView(_ uiView: MTKView, context: Context) { }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, MTKViewDelegate {
        var parent: MetalView
        
        init(_ parent: MetalView) {
            self.parent = parent
        }
        
        func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) { }
        
        func draw(in view: MTKView) {
            guard let drawable = view.currentDrawable else { return }
            guard let descriptor = view.currentRenderPassDescriptor else { return }
            
            let commandQueue = parent.device?.makeCommandQueue()
            let commandBuffer = commandQueue?.makeCommandBuffer()
            let renderEncoder = commandBuffer?.makeRenderCommandEncoder(descriptor: descriptor)
            
            renderEncoder?.endEncoding()
            commandBuffer?.present(drawable)
            commandBuffer?.commit()
        }
        
        @objc func handlePinch(_ sender: UIPinchGestureRecognizer) {
            print("Pinch detected")
        }
        
        @objc func handleTap(_ sender: UITapGestureRecognizer) {
            print("Tap detected")
        }
    }
}

FB24093238

Pinch gesture not recognized on MTKView when attaching it to a RealityView using a ViewAttachmentComponent in a immersive space
 
 
Q