我在SwiftUI应用中使用SceneKit来显示从Blender导出的.scn
文件转换而来的某些.dae
文件。
正在使用UIViewRepresentable
显示SceneKit。
我正在显示逐步指导说明,并且每个步骤都包含一些文本和动画。每个动画都是其自己的.scn
文件,我将根据当前步骤交换场景文件。
我的问题是,当场景交换时,我需要对材质进行一些初始化,但是在发生这种情况时,仅调用updateUIView
,我不想在这里做这项工作,因为每次动画被调用时都会调用它。暂停等
我希望每次更换场景后都要进行一次这项工作,但是我正在努力用当前的实现方法来找到解决方案。
我认为我处理场景交换的方式不正确,但是我想知道是否有人可以将我指向正确的方向。
谢谢!
请参见下面的完整代码:
struct MaintenanceFlowDetailView: View {
var maintenanceFlow: MaintenanceFlow
@State private var currentStepIndex = 0
@State private var pauseAnimation = false
func stepBackwards() {
currentStepIndex -= 1
pauseAnimation = false
}
func stepForwards() {
currentStepIndex += 1
pauseAnimation = false
}
func togglePauseAnimation() {
pauseAnimation = !pauseAnimation
}
var body: some View {
NavigationView{
VStack(alignment: .leading, spacing: 12){
SceneKitView(sceneFilePath: maintenanceFlow.steps[currentStepIndex].scenePath, pauseAnimation: $pauseAnimation)
.frame(height: 300)
Text(maintenanceFlow.steps[currentStepIndex].text)
Spacer()
HStack{
if currentStepIndex > 0 {
Button(action: stepBackwards) {
Text("Back")
}
}
Spacer()
Button(action: togglePauseAnimation) {
Text(pauseAnimation ? "Play" : "Pause")
}
Spacer()
if currentStepIndex < maintenanceFlow.steps.count - 1 {
Button(action: stepForwards) {
Text("Next")
}
}
}
}.padding()
.navigationBarTitle(Text(maintenanceFlow.name))
}
}
}
struct SceneKitView : UIViewRepresentable {
var sceneFilePath: String
@Binding var pauseAnimation: Bool
func makeUIView(context: Context) -> SCNView {
print("calling CREATE view")
// I NEED TO INITIALISE MATERIALS ETC JUST ONCE HERE...
let scnView = SCNView()
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("calling UPDATE view")
// BUT THE SCENE IS REPLACED HERE :(
let scene = SCNScene(named: sceneFilePath)!
scene.isPaused = pauseAnimation
scnView.scene = scene
scnView.showsStatistics = true
}
}
使用以下内容:
struct SceneKitView : UIViewRepresentable {
var sceneFilePath: String
@Binding var pauseAnimation: Bool
func makeUIView(context: Context) -> SCNView {
print("calling CREATE view")
let scnView = SCNView()
let scene = SCNScene(named: sceneFilePath)
scnView.scene = scene
scnView.showsStatistics = true
return scnView
}
func updateUIView(_ scnView: SCNView, context: Context) {
print("calling UPDATE view")
scnView.scene?.isPaused = pauseAnimation
}
}
更新:进行了一些纠正,但是想法是相同的。已通过Xcode 11.4 / iOS 13.4测试。更改SceneKitView
时会重新创建sceneFilePath:
,因此,如果未更新,则是另一个代码问题。
这里使用测试视图:
struct TestSceneKitView: View {
@State private var filePath = "test1"
var body: some View {
VStack {
Button("Push") { self.filePath = "test2" }
SceneKitView(sceneFilePath: filePath, pauseAnimation: .constant(false))
}
}
}