SwiftUI中如何实现暂停AR会话并清理变量与锚点的功能?
解决方案
我们可以通过绑定状态传递信号+引用类型协调器管理AR资源的方式实现暂停AR会话、清理字典和移除锚点的功能,以下是具体修改步骤和代码:
1. 重构ARExperience结构体
将AR视图、实体字典移到Coordinator(引用类型)中,避免值类型结构体的副本问题,同时添加绑定变量和清理函数:
struct ARExperience: UIViewRepresentable { // 绑定主视图的停止信号 @Binding var shouldStopAR: Bool func makeCoordinator() -> Coordinator { Coordinator() } class Coordinator: NSObject, ARSessionDelegate { var arView: ARView! // 移到协调器中,确保修改实时生效 var entityDictionaries = [String: (anchor: AnchorEntity, model: ModelEntity)]() func session(_ session: ARSession, didAdd anchors: [ARAnchor]) { guard let validAnchor = anchors[0] as? ARImageAnchor else { return } let anchor = AnchorEntity(anchor: validAnchor) let videoPlane = createdVideoPlayerNodeFor(validAnchor.referenceImage) anchor.addChild(videoPlane) arView.scene.addAnchor(anchor) if let targetName = validAnchor.referenceImage.name { entityDictionaries[targetName] = (anchor, videoPlane) } } func session(_ session: ARSession, didUpdate anchors: [ARAnchor]) { // 保留你的更新逻辑 } // 核心清理函数 func cleanupARSession() { // 1. 暂停AR会话 arView.session.pause() // 2. 从场景中移除所有锚点实体 for (_, value) in entityDictionaries { arView.scene.removeAnchor(value.anchor) // 可选:停止视频播放,释放资源 // (如果你的videoPlane包含AVPlayer,这里需要调用player.pause()) } // 3. 清空实体字典 entityDictionaries.removeAll() // 可选:彻底移除AR会话中的原生锚点 arView.session.currentFrame?.anchors.forEach { anchor in arView.session.remove(anchor: anchor) } } } func makeUIView(context: Context) -> ARView { let arView = ARView(frame: .zero) context.coordinator.arView = arView arView.session.delegate = context.coordinator // 在这里配置你的AR会话(比如ARImageTrackingConfiguration) return arView } func updateUIView(_ uiView: ARView, context: Context) { // 监听停止信号,触发清理 if shouldStopAR { context.coordinator.cleanupARSession() // 重置信号,避免重复触发 shouldStopAR = false } } // 保留你的视频节点创建函数 private func createdVideoPlayerNodeFor(_ referenceImage: ARReferenceImage) -> ModelEntity { let plane = ModelEntity(mesh: .generatePlane(width: referenceImage.physicalSize.width, height: referenceImage.physicalSize.height)) // 补充你的视频播放器配置逻辑 return plane } }
2. 修改主视图InitiateARView
添加状态变量绑定到ARExperience,点击按钮时触发停止信号:
struct InitiateARView: View { @StateObject var vm = ARPreparationViewModel() // 管理AR停止状态 @State private var shouldStopAR = false var body: some View { VStack { if vm.isLoading { Button("Start", action: { vm.prepareAR() }) } else { ZStack { // 传递绑定状态 ARExperience(shouldStopAR: $shouldStopAR) .edgesIgnoringSafeArea(.all) VStack { HStack { Spacer() Button("Stop AR", action: { // 触发停止信号 shouldStopAR = true }) } Spacer() } } } } } }
关键逻辑说明
- 绑定状态传递:通过
@Binding在主视图和ARExperience之间传递停止信号,实现跨组件的事件触发。 - 引用类型协调器:将AR视图、实体字典放在
Coordinator(类类型)中,避免结构体值传递导致的副本失效问题,确保修改实时生效。 - 完整清理流程:暂停会话→移除场景锚点→清空字典→可选移除原生锚点,确保AR资源被彻底释放。
内容的提问来源于stack exchange,提问作者user1207524
相关产品推荐
相关产品推荐

