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

visionOS窗口固定宽高比问题:Resize Control行为不协调求解

visionOS 实现固定宽高比且支持缩放的窗口

一、你之前的代码为什么失效

直接通过UIApplication.shared.windows.first修改窗口frame是错误的实现方式:

  • visionOS的窗口由SwiftUI的WindowGroup声明式管理,手动操作UIKit层级的窗口会破坏SwiftUI的状态同步机制,导致后续交互无响应。
  • GeometryReader获取的是ContentView的内部尺寸,而非窗口的实际尺寸,以此计算窗口宽高会导致逻辑错位。

二、正确实现固定宽高比+可缩放窗口

采用SwiftUI原生的布局修饰符和窗口配置,无需手动操作UIKit窗口:

1. 基础实现:锁定宽高比并允许缩放

import SwiftUI
import RealityKit

let targetAspectRatio: CGFloat = 16/9 // 自定义你的目标宽高比

@main
struct VisionOSWindowApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
                // 锁定宽高比,contentMode设为.fit确保内容按比例适配
                .aspectRatio(targetAspectRatio, contentMode: .fit)
                // 设置窗口可调整的最小/最大尺寸范围,确保缩放操作有效
                .frame(
                    minWidth: 300,
                    minHeight: 300 / targetAspectRatio,
                    maxWidth: 1200,
                    maxHeight: 1200 / targetAspectRatio
                )
                // 允许用户通过Resize Control调整窗口尺寸
                .windowResizability(.contentSize)
        }
    }
}

struct ContentView: View {
    var body: some View {
        // RealityView会自适应父视图的尺寸,无需额外处理
        RealityView { content in
            // 添加你的RealityKit内容
            let entity = ModelEntity(mesh: .generateBox(size: 0.5))
            content.add(entity)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.gray.opacity(0.1))
    }
}

2. 进阶:动态保持宽高比(用户拖动时自动修正比例)

如果需要在用户拖动Resize Control时严格保持宽高比(即使拖动过程中临时偏离,松开后自动修正),可以监听窗口尺寸变化并调整:

@main
struct VisionOSWindowApp: App {
    @State private var windowSize: CGSize = .init(width: 600, height: 600 / targetAspectRatio)
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .aspectRatio(targetAspectRatio, contentMode: .fit)
                .frame(width: windowSize.width, height: windowSize.height)
                .windowResizability(.contentSize)
                // 监听窗口实际尺寸变化
                .onChange(of: UIApplication.shared.windows.first?.frame.size) { newSize in
                    guard let newSize = newSize, newSize != .zero else { return }
                    // 计算符合宽高比的修正尺寸
                    let correctedHeight = newSize.width / targetAspectRatio
                    let correctedWidth = newSize.height * targetAspectRatio
                    // 选择偏差较小的方向修正(避免反复切换)
                    if abs(newSize.height - correctedHeight) < abs(newSize.width - correctedWidth) {
                        windowSize = .init(width: newSize.width, height: correctedHeight)
                    } else {
                        windowSize = .init(width: correctedWidth, height: newSize.height)
                    }
                }
        }
    }
}

三、RealityView的影响说明

RealityView本身不会加剧窗口尺寸问题:

  • 只要给RealityView设置.frame(maxWidth: .infinity, maxHeight: .infinity),它会自动适配父视图的尺寸,跟随窗口缩放同步变化。
  • 若出现布局异常,通常是RealityView内部内容未设置正确的锚点或缩放模式,可通过调整RealityKit实体的scale或position属性解决。

四、关键注意事项

  • 永远不要直接操作UIKit的UIWindow实例来修改SwiftUI窗口尺寸,这会破坏声明式布局的状态一致性。
  • 宽高比的锁定要结合窗口的最小/最大尺寸设置,确保Resize Control有可操作的范围。
  • 若需要更精细的窗口控制,可以使用UIWindowSceneDelegate的windowScene(_:didUpdate:)方法,但需注意与SwiftUI状态的同步。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 20:12:37