VisionPro开发实践2 - 构建数据模型

1. 定义数据对象

创建一个Model文件夹,并在其中添加Bag文件,内容如下:

rust 复制代码
struct Bag: Identifiable, Codable, Hashable {
    let id: Int
    let name: String
    let title: String
    let desc: String
}

2. 通过JSON文件加载数据

2.1. 定义ViewModel

在Model文件夹下新建一个ViewModel文件,内容如下:

typescript 复制代码
import Foundation

class BagViewModel: ObservableObject {
    @Published var bags: [Bag] = []
    
    init() {
        load()
    }
    
    func load() {
        if let url = Bundle.main.url(forResource: "bags", withExtension: "json"),
           let data = try? Data(contentsOf: url),
           let bags = try? JSONDecoder().decode([Bag].self, from: data) {
            self.bags = bags
        }
    }
}

这里声明了一个 ObserverableObject,用来加载JSON文件中的内容,并用于UI界面的展示,后面会讲到应用场景。

这个BagViewModel对象中定一个了一个bags的Bag数组对象,用来保存从文件中读取的数据。

2.2. 创建JSON文件

在根目录下创建一个bag.json的文件,并根据之前的Bag模型来定义数据,数据案例如下:

css 复制代码
[  {    "id": 1,    "name": "Speedy",    "title": "LV x YK SPEEDY BANDOULIÈRE 20 手袋",    "desc": "路易威登 x 草间弥生合作系列推出 LV x YK Speedy Bandoulière 20 手袋,迸发无限波点主题的创意能量。鲜明波点经由丝印工艺呈现于 Monogram Empreinte 牛皮革之上,呼应这位知名日本艺术家作品中的一贯主题,礼赞艺术思维与精湛匠艺的结合。南瓜形状装饰再添草间弥生的视觉名片。"  },  {    "id": 2,    "name": "Neonoe",    "title": "NÉONOÉ 中号手袋 大象灰/奶白色 压纹粒面牛皮",    "desc": "本款 NéoNoé 中号水桶包将 LV 字母和 Monogram 花卉先印染后压印于皮革,以瞩目观感迷惑视觉。内袋可妥善安置贵重物品,可调节肩带实现肩背或斜挎。"  }]

本文件的加载与上文提到的

less 复制代码
Bundle.main.url(forResource: "bags", withExtension: "json")

语句相对应。

2.3. 数据应用

先看一下界面效果,通过加载JSON文件,把bags数组呈现在右侧边栏中

less 复制代码
struct ContentView: View {
    
    @EnvironmentObject var store: ViewStore
    @EnvironmentObject var viewModel: BagViewModel

    var body: some View {
        
        NavigationSplitView {
            List(viewModel.bags, id: .self.id, selection: $store.selection) { bag in
                HStack(alignment: .center) {
                    Model3D(named: bag.name, bundle: realityKitContentBundle)
                        .frame(width: 20, height: 20)
                        .frame(depth: 10, alignment: .center)
                        .rotation3DEffect(Angle(degrees: bag.name == "DAUPHINE" ? 179: 0), axis: .y)
                        .scaleEffect(x: 0.1, y: 0.1, z: 0.1)
                        .padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
                        
                    Text("(bag.title)")
                }
            }
        } detail: {
            ItemDetailView()
        }
        .environmentObject(store)
        .environmentObject(viewModel)
        
    }
}

3. 数据传递

因为我要在多个View之间传递数据,目前没想到更好的办法,就先用EnviromentObject来进行环境变量传递。

可以看到在上文中,ContentView就是用这种方式加载了环境变量viewModel和store,那么这两个环境变量是在哪里初始化的呢? 我们看一下APP的初始View:

scss 复制代码
import SwiftUI

@main
struct VisionBagApp: App {
    @StateObject var store = ViewStore()
    @ObservedObject var viewModel = BagViewModel()
    
    var body: some Scene {
        
        WindowGroup {
            ContentView()
                .environmentObject(store)
                .environmentObject(viewModel)
        }

        ImmersiveSpace(id: "ImmersiveSpace") {
            ImmersiveView()
                .environmentObject(store)
                .environmentObject(viewModel)
        }
        
    }
    
    init() {
        // Register all the custom components and systems that the app uses.
        RotationComponent.registerComponent()
        RotationSystem.registerSystem()
        TraceComponent.registerComponent()
        TraceSystem.registerSystem()
    }
}

在这里完成了store和viewModel的初始化,尤其是viewModel会在这里完成JSON文件的读取。并传递到下一级的View当中。

这里我们就完成了数据模型的创建和展示,后面的文章会具体讲一下VisionOS的ImmersiveSpace和一些操作3D手势。

相关推荐
hpysirius6 小时前
从零构建 Web 端视频剪辑器:技术实践与思考
前端
让学习成为一种生活方式6 小时前
大肠杆菌合成扑热息痛--对乙酰氨基酚--文献精读227
开发语言·前端·javascript
李白的天不白6 小时前
请求不到百度网址的原因
前端
Gary Studio6 小时前
Selinux编写
linux·服务器·前端
北京自在科技6 小时前
Find Hub App 小更新
android·ios·安卓·findmy·airtag
网络点点滴6 小时前
NPM的包版本管理
前端·npm·node.js
光影少年7 小时前
react性能优化比较好的办法有哪些?
前端·react.js·性能优化
fix一个write十个7 小时前
从零搭建音视频通话太痛苦?这个 Vue3 CallKit 让你 5 分钟搞定 1v1 + 群聊通话
前端·vue.js·github
豹哥学前端7 小时前
告别割裂式学习:待办清单项目,一次性掌握数组、本地存储与事件委托
前端·javascript
JYeontu7 小时前
照片墙太死板?做一个会随风摇摆的绳串图片交互效果
前端·javascript·css