swiftswiftuirealitykitreality-composer

How to make a text appear on the screen after pressing the button?


I want to make the text display on the screen according to the different scenes after pressing the button. For example, if model A is displayed, text "A" will be appeared on the screen. Similarly, if model B is displayed, text "B" will also be appeared. I am currently creating Augmented Reality app using SwiftUI interface and RealityKit but not sure what to do in the next step.

Here is my code:

import SwiftUI
import RealityKit

struct ContentView : View {
    
    @State var arView = ARView(frame: .zero)
    
    var body: some View {
        ZStack {
            ARViewContainer(arView: $arView)
            HStack {
                Spacer()
                Button("information") {
                    print(self.arView.scene.name)
                    print(arView.scene.anchors.startIndex)
                    print(arView.scene.anchors.endIndex)
                }
                Spacer()
                Button("remove") {
                    stop()
                }
                Spacer()
            }
        } .edgesIgnoringSafeArea(.all)
    }
    func stop() {
        arView.scene.anchors.removeAll()
    }
}

struct ARViewContainer: UIViewRepresentable {
    
    @Binding var arView: ARView
    
    func makeUIView(context: Context) -> ARView {
        
        let boxAnchor = try! Experience1.loadBox()
        let crownAnchor = try! Experience1.loadCrown()       
        arView.scene.anchors.append(boxAnchor)
        arView.scene.anchors.append(crownAnchor)        
        return arView  
    }
    func updateUIView(_ uiView: ARView, context: Context) { }
}

From the code above, if boxAnchor and crownAnchor and displayed, text "Box" and "Crown" will be appeared on the screen respectively. Anyone who knows how to do that please guide me or suggest a tutorial that I can use to study.

Sorry if I use the wrong technical terms. Thank you


Solution

  • Use Combine's reactive subscriber and MVVM's bindings to update string values for Text views.

    import SwiftUI
    import RealityKit
    import Combine
    
    struct ContentView : View {
        
        @State private var arView = ARView(frame: .zero)
        @State private var str01: String = "...some text..."
        @State private var str02: String = "...some text..."
        
        var body: some View {
            ZStack {
                ARViewContainer(arView: $arView, str01: $str01, str02: $str02)
                    .ignoresSafeArea()
                VStack {
                    Spacer()
                    Text(str01)
                        .foregroundColor(.white)
                        .font(.largeTitle)
                    Divider()
                    Text(str02)
                        .foregroundColor(.white)
                        .font(.largeTitle)
                    Spacer()
                }
            }
        }
    }
    

    The miracle happens in the escaping closure of subscribe(to:) instance method. What will be the conditions in the if-statements is up to you.

    struct ARViewContainer: UIViewRepresentable {
        
        @Binding var arView: ARView
        @Binding var str01: String
        @Binding var str02: String
        @State var subs: [AnyCancellable] = []
        
        func makeUIView(context: Context) -> ARView {
            let boxAnchor = try! Experience.loadBox()
            let crownAnchor = try! Experience.loadCrown()
    
            print(arView.scene.anchors.count)
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
                arView.scene.anchors.append(boxAnchor)
                arView.scene.anchors.append(crownAnchor)
                print(arView.scene.anchors.count)
            }
            return arView
        }
        func updateUIView(_ view: ARView, context: Context) {
            DispatchQueue.main.async {
                _ = view.scene.subscribe(to: SceneEvents.DidAddEntity.self) { _ in
                    if view.scene.anchors.count > 0 {
                        if view.scene.anchors[0].isAnchored {
                            str01 = "Crown"
                            str02 = "Cube"
                        }
                    }
                }.store(in: &subs)
            }
        }
    }
    

    enter image description here