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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:07:08