RealityKit与VisionOS中实现实体的视线悬停响应
在VisionOS的RealityKit中实现实体视线悬停响应
要给RealityKit实体添加视线悬停响应,主要有两种可行方案,直接用苹果官方API就能实现:
方案1:结合SwiftUI焦点状态绑定实体
利用SwiftUI的FocusState和EntityView,把SwiftUI原生的视线焦点检测能力附加到RealityKit实体上,复用成熟的交互逻辑。
示例代码:
struct HoverableRealityView: View { @FocusState private var focusedEntity: Entity? var body: some View { RealityView { content in // 创建3D按钮实体 let buttonEntity = ModelEntity( mesh: .generateBox(size: 0.1), materials: [SimpleMaterial(color: .gray, isMetallic: true)] ) content.add(buttonEntity) } update: { content in for entity in content.entities { // 用EntityView包裹实体,绑定焦点状态 EntityView(entity) { Color.clear .focusable() .focused($focusedEntity, equals: entity) .onChange(of: focusedEntity) { old, new in guard let modelEntity = entity as? ModelEntity else { return } if new == entity { // 悬停时切换高亮材质 modelEntity.model?.materials = [SimpleMaterial(color: .cyan, isMetallic: true)] } else if old == entity { // 失去焦点恢复原材质 modelEntity.model?.materials = [SimpleMaterial(color: .gray, isMetallic: true)] } } } } } } }
方案2:直接使用RealityKit的FocusComponent
RealityKit原生提供FocusComponent,给实体添加该组件后,可监听FocusStateChangedEvent处理悬停的触发与取消,完全在RealityKit生态内实现,无需依赖SwiftUI视图。
示例代码:
struct RealityKitFocusView: View { var body: some View { RealityView { content in let buttonEntity = ModelEntity( mesh: .generateBox(size: 0.1), materials: [SimpleMaterial(color: .gray, isMetallic: true)] ) // 给实体添加FocusComponent,启用视线焦点检测 buttonEntity.components[FocusComponent.self] = FocusComponent() content.add(buttonEntity) // 订阅焦点变化事件 content.subscribe(to: FocusStateChangedEvent.self) { event in guard let modelEntity = event.entity as? ModelEntity else { return } if event.isFocused { // 悬停时添加发光效果 let glowingMaterial = SimpleMaterial( color: .white, isMetallic: false, roughness: 0.0, emissiveColor: .cyan ) modelEntity.model?.materials = [glowingMaterial] } else { // 恢复原材质 modelEntity.model?.materials = [SimpleMaterial(color: .gray, isMetallic: true)] } } } } }
补充说明
应用商店里的3D按钮发光效果,两种方案都能实现:
- 如果需要叠加复杂UI元素(比如文字提示、自定义按钮样式),可以用方案1结合SwiftUI视图;
- 如果只需要纯3D实体的悬停反馈,方案2更轻量、性能更好。
另外,可将材质修改代码包裹在withAnimation(.easeInOut(duration: 0.2))中,让过渡效果更平滑自然。
内容的提问来源于stack exchange,提问作者Toby Evetts
相关产品推荐
相关产品推荐

