You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Xcode中为visionOS开发的Model Entity实现悬停触发操作的方法

解决visionOS中ModelEntity聚焦/失焦回调与高亮问题

你遇到的问题核心是:onHover是SwiftUI View的专属方法,RealityKit的ModelEntity并没有这个API,所以直接调用会报错。下面提供两种可行的解决方案,同时实现高亮效果和聚焦/失焦回调:

方案一:用SwiftUI HoverGesture结合RealityView更新

通过SwiftUI手势监听实体聚焦状态,再在RealityView的update闭包里同步更新实体外观,同时触发回调函数:

struct ContentView: View {
    @State private var hoveredEntityName: String?
    let uniformedScale: Float = 0.1
    
    enum LightIDs: String, CaseIterable {
        case light1, light2, light3
    }
    
    var body: some View {
        ZStack {
            RealityView { content, attachments in
                // 批量创建实体
                for lightID in LightIDs.allCases {
                    let model = ModelEntity(
                        mesh: .generateSphere(radius: uniformedScale),
                        materials: [SimpleMaterial(color: .red, isMetallic: false)]
                    )
                    
                    let x = Float.random(in: -1.0 ... 1.0)
                    model.position = SIMD3(x, 1.0, -2.0)
                    
                    model.name = lightID.rawValue
                    model.components.set(InputTargetComponent())
                    model.components.set(HoverEffectComponent())
                    model.components.set(CollisionComponent(shapes: [.generateSphere(radius: uniformedScale)]))
                    content.add(model)
                }
            } update: { content, attachments in
                // 根据聚焦状态更新实体材质
                for entity in content.entities {
                    guard let modelEntity = entity as? ModelEntity else { continue }
                    let isHovered = modelEntity.name == hoveredEntityName
                    modelEntity.model?.materials = [
                        SimpleMaterial(
                            color: isHovered ? .lightBlue : .red,
                            isMetallic: false
                        )
                    ]
                }
            }
            .gesture(
                HoverGesture()
                    .targetedToAnyEntity()
                    .onChanged { value in
                        let entityName = value.entity.name
                        hoveredEntityName = entityName
                        handleFocus(entityName: entityName)
                    }
                    .onEnded { _ in
                        guard let entityName = hoveredEntityName else { return }
                        hoveredEntityName = nil
                        handleBlur(entityName: entityName)
                    }
            )
        }
    }
    
    // 聚焦回调函数
    private func handleFocus(entityName: String) {
        print("聚焦实体:\(entityName)")
        // 这里添加你的业务逻辑
    }
    
    // 失焦回调函数
    private func handleBlur(entityName: String) {
        print("失焦实体:\(entityName)")
        // 这里添加你的业务逻辑
    }
}

方案二:RealityKit原生InputTargetComponent事件处理

直接给InputTargetComponent绑定事件闭包,原生响应hoverEnter和hoverExit事件,更贴合RealityKit的处理逻辑:

struct ContentView: View {
    let uniformedScale: Float = 0.1
    
    enum LightIDs: String, CaseIterable {
        case light1, light2, light3
    }
    
    var body: some View {
        ZStack {
            RealityView { content in
                for lightID in LightIDs.allCases {
                    let model = ModelEntity(
                        mesh: .generateSphere(radius: uniformedScale),
                        materials: [SimpleMaterial(color: .red, isMetallic: false)]
                    )
                    
                    let x = Float.random(in: -1.0 ... 1.0)
                    model.position = SIMD3(x, 1.0, -2.0)
                    
                    model.name = lightID.rawValue
                    
                    // 绑定InputTarget事件处理
                    let inputTarget = InputTargetComponent { entity, event in
                        switch event {
                        case .hoverEnter:
                            // 聚焦时更新材质+触发回调
                            model.model?.materials = [SimpleMaterial(color: .lightBlue, isMetallic: false)]
                            handleFocus(entityName: entity.name)
                        case .hoverExit:
                            // 失焦时恢复材质+触发回调
                            model.model?.materials = [SimpleMaterial(color: .red, isMetallic: false)]
                            handleBlur(entityName: entity.name)
                        default:
                            break
                        }
                    }
                    model.components.set(inputTarget)
                    
                    model.components.set(HoverEffectComponent())
                    model.components.set(CollisionComponent(shapes: [.generateSphere(radius: uniformedScale)]))
                    content.add(model)
                }
            }
        }
    }
    
    private func handleFocus(entityName: String) {
        print("聚焦实体:\(entityName)")
        // 业务逻辑
    }
    
    private func handleBlur(entityName: String) {
        print("失焦实体:\(entityName)")
        // 业务逻辑
    }
}

关键注意事项

  • 必须确保实体添加了InputTargetComponent、CollisionComponent和HoverEffectComponent,这是接收眼睛聚焦事件的前提。
  • 两种方案都可以实现高亮+回调的需求,方案二更轻量化,直接在RealityKit层处理事件;方案一适合需要和SwiftUI状态深度绑定的场景。

内容的提问来源于stack exchange,提问作者Vi Tiet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:39:54