SwiftUI – 将数据从 SwiftUIView 传递到 SceneKit
Posted
技术标签:
【中文标题】SwiftUI – 将数据从 SwiftUIView 传递到 SceneKit【英文标题】:SwiftUI – Passing data from SwiftUIView to SceneKit 【发布时间】:2020-06-20 06:30:07 【问题描述】:目标: 使用 Scenekit (UIViewRepresentable) 控制 SwiftUI 视图的 SwiftUI 切换按钮
//显示fps和计时信息等统计信息
我做了什么: 这是 UIViewRepresentable ScenekitView
import SwiftUI
import SceneKit
struct ScenekitView : UIViewRepresentable
let scene = SCNScene(named: "art.scnassets/ship.scn")!
func makeUIView(context: Context) -> SCNView
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = .ambient
ambientLightNode.light!.color = UIColor.darkGray
scene.rootNode.addChildNode(ambientLightNode)
// retrieve the ship node
let ship = scene.rootNode.childNode(withName: "ship", recursively: true)!
// animate the 3d object
ship.runAction(SCNAction.repeatForever(SCNAction.rotateBy(x: 0, y: 2, z: 0, duration: 1)))
// retrieve the SCNView
let scnView = SCNView()
return scnView
func updateUIView(_ scnView: SCNView, context: Context)
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = true
// show statistics such as fps and timing information
scnView.showsStatistics = true
// configure the view
scnView.backgroundColor = UIColor.black
struct ScenekitView_Previews: PreviewProvider
static var previews: some View
ScenekitView()
这是控制 Scenekit 的菜单
import SwiftUI
struct Menu: View
@State var showstats = false
var body: some View
HStack
Form
Toggle(isOn:)
Text("Stats")
.frame(width: 200.0)
Spacer()
struct Menu_Previews: PreviewProvider
static var previews: some View
Menu()
这是主场景,菜单位于 Scenekit 之上:
import SwiftUI
struct MainView: View
var body: some View
ZStack
ScenekitView()
Menu()
问题:如何将数据从 ScenekitView 传递到菜单,以便切换和显示/隐藏统计信息?
我尝试了 ObservableObject 但无法使其工作。还查看了其他 SO 线程,但没有一个对我有用。
非常感谢任何帮助!
向大家干杯
【问题讨论】:
您正在寻找的是一个协调器,如 Apples SwiftUI 教程中所示:developer.apple.com/tutorials/swiftui/interfacing-with-uikit 您不应该,而是创建视图模型(作为 ObservableObject)并在菜单和场景中传递它,因此从任何位置修改该视图模型两个视图都可以做出相应的反应。 【参考方案1】:更新:2020 年 3 月 11 日。
要将数据传递给
updateNSView(_:context:)
或updateUIView(_:context:)
实例方法,您需要创建@State
和@Binding
属性。
使用以下代码了解如何操作:
我已经为 macOS 编写了这段代码,但您可以轻松地为 ios 更改它:
import SwiftUI
import SceneKit
struct ContentView: View
@State var stats: Bool = true
var body: some View
HStack
ScenekitView(showStats: $stats)
VStack
Button(action:
self.stats.toggle()
, label:
Text(self.stats ? "ON" : "OFF")
)
.frame(width: 150.0)
struct ScenekitView: NSViewRepresentable
@Binding var showStats: Bool
let sceneView = SCNView(frame: .zero)
let scene = SCNScene(named: "art.scnassets/ship.scn")!
func scnScene(stat: Bool, context: Context) -> SCNView
sceneView.scene = scene
sceneView.showsStatistics = stat
return sceneView
func makeNSView(context: Context) -> SCNView
scnScene(stat: true, context: context)
func updateNSView(_ uiView: SCNView, context: Context)
uiView.allowsCameraControl = true
uiView.backgroundColor = NSColor.black
uiView.showsStatistics = showStats
此外,您还可以使用
Coordinator
对象和delegate
到此协调器,以使用control
属性切换对象,并在renderer()
方法内以 60 fps 更新任何内容(例如)。
在这种情况下您不需要使用updateNSView()
或updateUIView()
方法:
struct ScenekitView: NSViewRepresentable
@Binding var showStats: Bool
let sceneView = SCNView(frame: .zero)
let scene = SCNScene(named: "art.scnassets/ship.scn")!
func makeCoordinator() -> Coordinator
Coordinator(self)
final class Coordinator: NSObject, SCNSceneRendererDelegate
var control: ScenekitView
init(_ control: ScenekitView)
self.control = control
func renderer(_ renderer: SCNSceneRenderer,
updateAtTime time: TimeInterval)
control.sceneView.showsStatistics = control.showStats
for i in 0...255
control.sceneView.backgroundColor = NSColor(
red: CGFloat(arc4random_uniform(UInt32(i))),
green: CGFloat(arc4random_uniform(UInt32(i))),
blue: CGFloat(arc4random_uniform(UInt32(i))),
alpha: 1.0)
func scnScene(stat: Bool, context: Context) -> SCNView
sceneView.scene = scene
sceneView.showsStatistics = stat
sceneView.delegate = context.coordinator
return sceneView
func makeNSView(context: Context) -> SCNView
scnScene(stat: true, context: context)
func updateNSView(_ uiView: SCNView, context: Context)
【讨论】:
以上是关于SwiftUI – 将数据从 SwiftUIView 传递到 SceneKit的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI – 将数据从 SwiftUIView 传递到 SceneKit
将数据从委托 Swift 类传递到 SwiftUI 结构中的 EnvironmentObject