如何在SwiftUI(非Cocoa)的macOS应用中设置容器窗口宽高比
解决SwiftUI WindowGroup窗口固定宽高比的问题
问题背景
环境:XCode 14.3.1,macOS Ventura 13.4.1
开发的时钟应用视图被约束为1:1宽高比,但容器窗口可自由调整尺寸(无宽高比限制),拉伸后视图显示效果不佳。当前使用WindowGroup而非直接操作NSWindow,仅能通过.frame()限制窗口宽高范围,无法固定宽高比,且找不到适配单窗口应用的自定义窗口方案。
当前代码:
import SwiftUI @main struct Mac_TestApp: App { var body: some Scene { WindowGroup { Overall_View() .frame(minWidth: 300, idealWidth: 500, maxWidth: 600, minHeight: 300, idealHeight: 500, maxHeight: 600) } .windowResizability(.contentSize) } }
解决方案
方法1:通过NSApplicationDelegateAdaptor关联代理设置宽高比
无需单独创建AppDelegate文件,直接在App结构体中声明代理类,获取窗口后添加宽高比约束:
import SwiftUI class AppDelegate: NSObject, NSApplicationDelegate { func applicationDidFinishLaunching(_ notification: Notification) { // 获取应用主窗口 guard let window = NSApplication.shared.windows.first else { return } // 锁定1:1宽高比 window.contentAspectRatio = NSSize(width: 1, height: 1) // 可选:设置窗口尺寸范围 window.minSize = NSSize(width: 300, height: 300) window.maxSize = NSSize(width: 600, height: 600) } } @main struct Mac_TestApp: App { // 关联自定义代理 @NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { Overall_View() } .windowResizability(.contentSize) } }
方法2:用NSWindowRepresentable自定义窗口(适配复杂需求)
如果需要更精细的窗口控制,可创建自定义NSWindow包装器,在其中设置宽高比:
import SwiftUI struct FixedAspectRatioWindow: NSWindowRepresentable { let content: () -> AnyView let aspectRatio: CGSize init(aspectRatio: CGSize = CGSize(width: 1, height: 1), @ViewBuilder content: @escaping () -> some View) { self.aspectRatio = aspectRatio self.content = { AnyView(content()) } } func makeNSWindow(context: Context) -> NSWindow { let window = NSWindow( contentRect: NSRect(x: 0, y: 0, width: 500, height: 500), styleMask: [.titled, .closable, .miniaturizable, .resizable], backing: .buffered, defer: false ) // 锁定宽高比 window.contentAspectRatio = aspectRatio // 设置尺寸范围 window.minSize = NSSize(width: 300, height: 300) window.maxSize = NSSize(width: 600, height: 600) window.center() window.contentView = NSHostingView(rootView: content()) return window } func updateNSWindow(_ window: NSWindow, context: Context) { // 更新窗口内容 if let hostingView = window.contentView as? NSHostingView<AnyView> { hostingView.rootView = content() } } } @main struct Mac_TestApp: App { var body: some Scene { WindowGroup { FixedAspectRatioWindow(aspectRatio: CGSize(width: 1, height: 1)) { Overall_View() } } } }
说明
- 两种方法均可实现窗口1:1宽高比锁定,调整窗口时会自动保持比例
- 方法1轻量化,适合简单需求;方法2适合需要自定义窗口样式、行为的场景
- 可根据需求修改
minSize和maxSize限制窗口缩放范围
内容的提问来源于stack exchange,提问作者Archie
相关产品推荐
相关产品推荐

