如何在visionOS中通过RealityView动态添加带Attachment的Entity?
在visionOS的RealityView中动态添加带Attachment的实体
实现思路
要动态添加带Attachment的Entity,核心是利用RealityView的update闭包响应ViewModel的状态变化,配合attachments闭包管理附件视图,最终将附件关联到新创建的实体上。
具体实现步骤
- 在ViewModel中维护待添加的实体配置队列,包含实体的位置、对应附件的标识等信息
- 在
attachments闭包中,基于ViewModel的附件配置动态生成带唯一标识的附件视图 - 在
update闭包中监听ViewModel的新增实体队列,创建实体并将对应附件绑定到实体的AttachmentComponent上,最后添加到根实体
完整代码示例
ViewModel部分
import SwiftUI import RealityKit class EntityViewModel: ObservableObject { let rootEntity = Entity() // 存储待添加的实体配置:UUID作为附件标识,position是实体位置 @Published var pendingEntities: [(id: UUID, position: SIMD3<Float>)] = [] // 存储每个附件对应的文本内容 @Published var attachmentTexts: [UUID: String] = [:] // 对外提供添加实体的方法 func addEntity(withText text: String, at position: SIMD3<Float>) { let id = UUID() pendingEntities.append((id: id, position: position)) attachmentTexts[id] = text } }
RealityView部分
struct DynamicAttachmentDemoView: View { @StateObject private var viewModel = EntityViewModel() var body: some View { RealityView { content, attachments in content.add(viewModel.rootEntity) } update: { content, attachments in // 处理待添加的实体队列 guard !viewModel.pendingEntities.isEmpty else { return } for entityConfig in viewModel.pendingEntities { // 创建载体实体(示例用立方体) let entity = ModelEntity(mesh: .generateBox(size: 0.1)) entity.position = entityConfig.position // 通过UUID获取对应的附件实体 if let attachmentEntity = attachments.entity(for: entityConfig.id) { // 创建AttachmentComponent并绑定到载体实体 let attachmentComponent = AttachmentComponent( entity: attachmentEntity, placement: .plane(.front, width: 0.1, height: 0.1) ) entity.components.set(attachmentComponent) } // 将实体添加到根实体 viewModel.rootEntity.addChild(entity) } // 清空待添加队列,避免重复处理 viewModel.pendingEntities.removeAll() } attachments: { // 动态生成所有需要的附件视图,用UUID作为唯一标识 ForEach(Array(viewModel.attachmentTexts.keys), id: \.self) { id in Text(viewModel.attachmentTexts[id] ?? "默认文本") .font(.caption) .padding(4) .background(.white) .cornerRadius(4) .tag(id) } } .gesture(addEntityGesture()) } // 自定义添加实体的手势(示例:点击屏幕添加) private func addEntityGesture() -> some Gesture { TapGesture() .onEnded { // 生成随机位置 let randomPos = SIMD3<Float>( Float.random(in: -0.5...0.5), Float.random(in: -0.5...0.5), Float.random(in: -0.5...0.5) ) // 调用ViewModel方法添加实体 viewModel.addEntity(withText: "动态附件 \(UUID().uuidString.prefix(5))", at: randomPos) } } }
关键注意点
- 唯一标识匹配:必须用唯一的值(比如UUID)作为附件的
tag,确保实体能准确绑定到对应的附件 - 状态驱动更新:依赖ViewModel的
@Published属性触发RealityView的update闭包,实现动态添加逻辑 - 附件绑定时机:只能在
update闭包中获取附件实体并绑定,因为attachments闭包的内容仅在视图更新时完成初始化
内容的提问来源于stack exchange,提问作者Gerry Gao
相关产品推荐
相关产品推荐

