You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中SceneKit场景无法自动刷新的解决方法咨询

解决SceneKit场景在SwiftUI中无法自动刷新的问题

你的问题核心是节点的显示逻辑仅在视图初始化时执行了一次,后续orderModel的状态变化无法触发场景更新。以下是修复方案和完整代码:

修复后的完整代码

import SwiftUI
import SceneKit
import CoreData

// 确保OrderViewModel的属性可被SwiftUI监听
class OrderViewModel: ObservableObject {
    @Published var upJow: Bool = false
    @Published var lowJow: Bool = false
}

struct ScullView: UIViewRepresentable {
    @Binding var scene: SCNScene?
    @EnvironmentObject var orderModel: OrderViewModel

    func makeUIView(context: Context) -> SCNView {
        let view = SCNView()
        
        view.allowsCameraControl = false
        view.autoenablesDefaultLighting = true
        view.antialiasingMode = .multisampling4X
        view.backgroundColor = .clear
        view.scene = scene
        
        // 初始化时设置一次节点状态
        updateNodeVisibility(in: view)
        
        return view
    }

    func updateUIView(_ uiView: SCNView, context: Context) {
        // 状态变化时自动触发,更新节点显示
        updateNodeVisibility(in: uiView)
    }
    
    // 抽离节点状态更新逻辑,复用代码
    private func updateNodeVisibility(in view: SCNView) {
        guard let scene = view.scene else { return }
        
        let lowJow = scene.rootNode.childNode(withName: "Mandibola", recursively: true)
        let upJow = scene.rootNode.childNode(withName: "up", recursively: true)
        
        lowJow?.isHidden = !orderModel.lowJow
        upJow?.isHidden = !orderModel.upJow
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator()
    }
    
    class Coordinator: NSObject {}
}

struct FormulaView: View {
    @State var scene: SCNScene? = .init(named: "scull.scn")
    @EnvironmentObject var orderModel: OrderViewModel
    @Namespace var animation
  
    var body: some View {
        VStack {
            ScullView(scene: $scene)
                .frame(width: 500, height: 500, alignment: .top)
                .padding(.top, -50)
                .padding(.bottom, -15)
                .zIndex(-450)
            
            Spacer()
            
            VStack {
                Toggle("UJ", isOn: $orderModel.upJow)
                    .padding(.vertical, 10)
                Toggle("LJ", isOn: $orderModel.lowJow)
                    .padding(.vertical, 10)
            }
        }
        .padding()
    }
}

关键修改说明

  1. 复用节点更新逻辑:把原来仅在makeUIView中执行的节点显示判断,抽离为updateNodeVisibility方法,既用于初始化,也用于状态更新。
  2. 利用updateUIView触发刷新:SwiftUI的UIViewRepresentable中,updateUIView会在绑定状态(如orderModel的@Published属性)变化时自动调用,这里我们在该方法中更新节点的isHidden状态。
  3. 移除冗余视图实例:删除了ScullView中多余的let view = SCNView(),避免和makeUIView创建的视图混淆。
  4. 确保状态可监听:给orderModel的upJow和lowJow添加@Published包装器,让SwiftUI能检测到属性变化,进而触发ScullView的更新。

修改完成后,切换Toggle开关时,SceneKit场景中的对应节点会立即显示或隐藏,无需重新打开视图。

内容的提问来源于stack exchange,提问作者Adrian Shykunets

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 18:46:13