2

我想创建一个可滚动的 3D 模型列表(此处:Xcode 的默认船舶模型,您可以在 Xcode 的游戏项目中找到)。

为此,我创建了 3 个视图结构:

  • 一种用于查看 3D 模型(称为ScenekitView
  • 一个用于 CardView (称为MyCardView
  • 一个用于 3D 模型的可滚动列表(称为 MyCardsListView)

以下是结构:

ScenekitView (顺便说一句,我将Xcode 的默认游戏项目的art.scnassets文件夹添加到了我的Single View App项目中)

import SwiftUI
import SceneKit

struct ScenekitView : UIViewRepresentable {
    @Binding var yRotation : Float
    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.eulerAngles = SCNVector3(x: 0, y: self.yRotation * Float((Double.pi)/180.0) , z: 0)
        // 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
    }
}

#if DEBUG
struct ScenekitView_Previews : PreviewProvider {
    static var previews: some View {
        ScenekitView(yRotation: .constant(0))
    }
}
#endif

我的卡片视图

import SwiftUI

struct MyCardView : View {
    @Binding var yRotation: Float

    var body: some View {
        VStack(spacing: 0) {
            ZStack {
                Rectangle()
                    .foregroundColor(.black)
                    .opacity(0.8)
                    .frame(width:250, height: 70)
                Text( "Ship \( self.yRotation )" )
                    .foregroundColor(.white)
                    .font(.title)
                    .fontWeight(.bold)
            }
            ScenekitView(yRotation: self.$yRotation )
                .frame(width: 250, height: 250)
        }
        .cornerRadius(35)
        .frame(width: 250,height: 320)
    }
}

#if DEBUG
struct MyCardView_Previews : PreviewProvider {
    static var previews: some View {
        MyCardView(yRotation: .constant(90))
    }
}
#endif

我的卡片列表视图

import SwiftUI

struct MyCardsListView: View {
    @State var yRotation: Float = 0
    var body: some View {
        ScrollView(.horizontal, showsIndicators: false) {
            HStack {
                ForEach(0...2) { number in
                    GeometryReader { geometry in
                        MyCardView(yRotation: self.$yRotation )
                        .rotation3DEffect(Angle(degrees: Double(geometry.frame(in: .global).minX) / -20), axis: (x: 0, y: 10, z: 0))
                    }
                    .padding()
                    .frame(width: 250, height: 350)
                }
            }
        }
    }
}

#if DEBUG
struct Product3DView_Previews: PreviewProvider {
    static var previews: some View {
        MyCardsListView()
    }
}
#endif

MyCardsListView我得到每张卡片的最小 X 位置使用GeometryReader

我的目标是:

当我在MyCardsListView滚动卡片时,每个船模型都应该相对于其卡片的最小 X 位置旋转(它们都不应该同时以相同的旋转角度旋转)

(我知道我在使用绑定、状态等方面可能会犯很多错误,对此感到抱歉)

4

1 回答 1

2

你的代码有很多问题:

  1. 您永远不会为yRotation.
  2. 您在 中只有一个yRotation变量MyCardsListView,但是由于您希望根据视图的位置具有不同的旋转值,因此yRotation每个视图都需要一个变量。
  3. 以下行:
ship.eulerAngles = SCNVector3(x: 0, y: self.yRotation * Float((Double.pi)/180.0) , z: 0)

位于方法内部makeUIView(),但该方法仅执行一次(创建视图时)。您希望该值不断更新,因此您应该分配该值updateUIView()

您绝对应该观看 WWDC 会议226:SwiftUI 中的数据流231:集成 SwiftUI

于 2019-08-01T08:10:22.967 回答