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

visionOS中WindowGroup与ImmersiveSpace关联实现Mindfulness应用效果

实现visionOS Mindfulness应用的3D对象联动行为

核心思路

无需私有API,核心是通过窗口场景几何状态同步,将WindowGroup的空间位置与ImmersiveSpace中的3D对象绑定,结合SwiftUI环境变量、坐标转换和场景生命周期事件,控制对象的跟随/固定状态。

具体实现步骤

1. 监听窗口场景的几何变化

在WindowGroup视图中,通过@Environment(\.windowScene)获取窗口场景,监听其屏幕边界和方向变化,推导窗口在3D空间中的变换参数:

struct MindfulnessWindowView: View {
    @Environment(\.windowScene) private var windowScene: UIWindowScene?
    @Binding var windowTransform: Transform3D
    @Binding var sessionActive: Bool
    
    var body: some View {
        VStack {
            Text("Mindfulness Session")
            Button(sessionActive ? "结束会话" : "开始会话") {
                sessionActive.toggle()
            }
        }
        .onChange(of: windowScene?.screen.bounds) { _ in
            if !sessionActive { updateWindowTransform() }
        }
        .onChange(of: windowScene?.interfaceOrientation) { _ in
            if !sessionActive { updateWindowTransform() }
        }
    }
    
    private func updateWindowTransform() {
        guard let scene = windowScene else { return }
        let screenBounds = scene.screen.bounds
        // 将屏幕像素坐标转换为visionOS空间坐标(米为单位)
        let spatialX = (screenBounds.midX - UIScreen.main.bounds.midX) / 1200
        let spatialY = (screenBounds.midY - UIScreen.main.bounds.midY) / 1200
        // 让对象位于窗口后方0.5米处
        windowTransform = Transform3D(translationX: spatialX, y: spatialY, z: -0.5)
    }
}

2. 在ImmersiveSpace中同步变换状态

通过App结构体的@State变量共享窗口变换数据,在ImmersiveSpace视图中根据会话状态切换对象的变换规则:

@main
struct MindfulnessApp: App {
    @State private var windowTransform: Transform3D = .identity
    @State private var sessionActive = false
    
    var body: some Scene {
        WindowGroup {
            MindfulnessWindowView(
                windowTransform: $windowTransform,
                sessionActive: $sessionActive
            )
        }
        
        ImmersiveSpace(id: "MindfulnessSpace") {
            ImmersiveView(
                windowTransform: $windowTransform,
                sessionActive: $sessionActive
            )
        }
    }
}

struct ImmersiveView: View {
    @Binding var windowTransform: Transform3D
    @Binding var sessionActive: Bool
    @State private var fixedTransform: Transform3D = .identity
    
    var body: some View {
        Model3D(named: "meditation-object") { model in
            model
                .scaleEffect(0.4)
                .transform(sessionActive ? fixedTransform : windowTransform)
        } placeholder: {
            ProgressView("加载3D对象")
        }
        .onChange(of: sessionActive) { active in
            if active {
                // 会话开始时锁定当前位置
                fixedTransform = windowTransform
            }
        }
    }
}

关键细节说明

  • 坐标转换系数:示例中用1200作为像素到米的转换系数,可根据设备屏幕实际尺寸调整,确保3D对象准确对齐窗口后方。
  • 会话状态控制:会话激活后停止更新窗口变换,复用当前变换值固定对象位置;会话结束后恢复跟随逻辑。
  • 跨场景状态同步:通过@Binding在WindowGroup和ImmersiveSpace之间传递状态,保证两者行为一致。

内容的提问来源于stack exchange,提问作者Michal Černý

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:12:52