Home > Back-end >  How to open a SwiftUI view by tapping an entity in RealityKit?
How to open a SwiftUI view by tapping an entity in RealityKit?

Time:01-05

I am using SwiftUI with RealityKit. As displayed in the code below, I have a plane entity that when tapped simply prints the name of the entity. What approach should I take toward navigating to a new view when I tap the entity? It would be preferable to navigate as with a navigation link in a normal view, but if that is not possible then perhaps a fullScreenCover?

ARViewContainer.swift:

class Coordinator: NSObject {
    
    weak var view: ARView?
    
    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        
        guard let view = self.view else { return }
        
        let tapLocation = recognizer.location(in: view)
        
        if let entity = view.entity(at: tapLocation) as? ModelEntity {
            print(entity.name)
        }
        
    }
    
}


struct ARViewContainer: UIViewRepresentable {
    typealias UIViewType = ARView
    

    func makeUIView(context: Context) -> ARView{
        let arView = ARView(frame: .zero, cameraMode: .ar, automaticallyConfigureSession: true)
        
        context.coordinator.view = arView
                
        arView.addGestureRecognizer(UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap)))
        
        arView.scene.anchors.removeAll()
        

        let anchor = AnchorEntity()

        let plane = MeshResource.generatePlane(width: 1, height: 1)

        
        
        var material = UnlitMaterial()
        material.color = .init(tint: .white,
                            texture: .init(try! .load(named: "instagram")))
       

        let planeEntity = ModelEntity(mesh: plane, materials: [material])
        planeEntity.generateCollisionShapes(recursive: true)
        
        planeEntity.name = "Plane Entity"

        planeEntity.position.z -= 1.0
        planeEntity.setParent(anchor)
        arView.scene.addAnchor(anchor)
        
        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context){
        
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
}

ContentView.swift

struct ContentView: View {   
    @State var open = false
    
    var body: some View {
        NavigationView{
            ZStack {
                ARViewContainer()
                    .ignoresSafeArea(.all)
            }
        } 
    }
}

View I want to navigate to:

struct TestView : View {
    var body : some View {
        VStack{
            Text("Test View")
        }
    }
}

CodePudding user response:

Manage the state of the view in an observable object and modify it from your AR view.

struct ContentView: View {
    @ObservedObject var settings = Settings.shared

    var body: some View {
        NavigationView {
            ZStack {
                ARViewContainer()
                    .ignoresSafeArea(.all)

                NavigationLink("", isActive: $settings.shouldOpenDetailsView) {
                    TestView()
                }
            }
        }
    }
}

class Settings: ObservableObject {
    static let shared = Settings()

    @Published var shouldOpenDetailsView = false
}

class Coordinator: NSObject {
    weak var view: ARView?

    @objc func handleTap(_ recognizer: UITapGestureRecognizer) {
        guard let view = self.view else { return }

        let tapLocation = recognizer.location(in: view)

        if let entity = view.entity(at: tapLocation) as? ModelEntity {
            Settings.shared.shouldOpenDetailsView = true
        }
    }
}
  • Related