SceneKit切换.allowsCameraControl时保留视角不重置场景方法
问题根因
SwiftUI 原生提供的SceneView中,options是初始化阶段生效的配置参数,不支持动态响应式更新。每次修改传入的options值触发SwiftUI视图重绘时,底层会直接重新创建全新的SCNView实例,自动生成的相机控制节点会直接加载场景初始配置,之前调整好的视角、对象朝向就会全部重置。
解决方案
不要依赖SceneView的options参数切换相机控制状态,改用UIViewRepresentable自定义封装SCNView,在视图更新回调中动态修改allowsCameraControl属性,避免重建整个视图实例,即可完整保留当前相机状态。
实现代码
- 自定义可动态更新配置的SceneKit视图包装
import SwiftUI import SceneKit struct CustomSceneView: UIViewRepresentable { let scene: SCNScene @Binding var allowsCameraControl: Bool func makeUIView(context: Context) -> SCNView { let scnView = SCNView() scnView.scene = scene scnView.allowsCameraControl = allowsCameraControl // 可在此处补充你需要的其他SCNView默认配置,比如自动光照、背景色等 scnView.autoenablesDefaultLighting = true scnView.backgroundColor = .clear return scnView } func updateUIView(_ uiView: SCNView, context: Context) { // 仅动态修改目标属性,不销毁重建SCNView实例 uiView.allowsCameraControl = allowsCameraControl } }
- 修改原有业务代码,替换原生SceneView
final class Lmao: ObservableObject { // 直接绑定相机控制开关状态即可,不需要再存Options集合 @Published var allowsCameraControl: Bool = true } struct ContentView: View { @EnvironmentObject var l: Lmao // 注意实际项目中请对场景加载做安全解包处理 var scene = SCNScene(named: "myScene.scn")! var body: some View { VStack { CustomSceneView( scene: scene, allowsCameraControl: $l.allowsCameraControl ) .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height / 2) Button("allow/disable camera controll") { l.allowsCameraControl.toggle() } } } func updateLocation(_ location: CGPoint) { print(location) } }
App入口的代码不需要做任何修改。
补充说明
- 该方案切换相机控制状态时,底层
SCNView实例始终保持存活,相机节点的位置、旋转、缩放参数会完整保留,不会出现视角重置问题。 - 如果因特殊限制必须使用原生
SceneView,可以在切换options前先读取当前pointOfView节点的position、eulerAngles参数暂存,等视图重绘完成后再将参数赋值回新的相机节点,但是该方案会大概率出现轻微画面跳变,稳定性不如自定义封装方案。
内容的提问来源于stack exchange,提问作者Luca Phillips
相关产品推荐
相关产品推荐

