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

Swift5 macOS下如何编程将App窗口显示在主屏幕而非外接屏[Xcode15]

问题1:viewDidLoad中调整窗口位置无效的原因

viewDidLoad调用时,视图仅完成加载,尚未关联到所在的NSWindow实例,此时self.view.window的值为nil,所有调整窗口的代码都不会生效。

可行的窗口指定屏幕显示方案

你可以在NSViewController的viewDidAppear方法中执行窗口位置调整,或者直接在NSWindowController层面做配置,Swift 5下的可用代码如下:

方案1:在ViewController中调整

override func viewDidAppear() {
    super.viewDidAppear()
    guard let mainScreen = NSScreen.screens.first, let window = self.view.window else { return }
    // 计算窗口在主屏幕居中的位置
    let targetFrame = mainScreen.visibleFrame
    let windowSize = window.frame.size
    let targetOrigin = NSPoint(
        x: targetFrame.midX - windowSize.width / 2,
        y: targetFrame.midY - windowSize.height / 2
    )
    window.setFrameOrigin(targetOrigin)
}

方案2:在WindowController中调整(推荐)

如果是自定义NSWindowController,可以重写windowDidLoad方法:

override func windowDidLoad() {
    super.windowDidLoad()
    guard let mainScreen = NSScreen.screens.first, let window = self.window else { return }
    let targetFrame = mainScreen.visibleFrame
    let windowSize = window.frame.size
    let targetOrigin = NSPoint(
        x: targetFrame.midX - windowSize.width / 2,
        y: targetFrame.midY - windowSize.height / 2
    )
    window.setFrameOrigin(targetOrigin)
}

问题2:ViewController中无法控制窗口显隐的原因

你在applicationDidFinishLaunching中创建的windowController是局部变量,函数执行完成后该实例会被ARC自动释放,对应的窗口也会被销毁,ViewController中拿到的self.view.window已经是无效对象,自然无法控制显隐。

修正方案

在AppDelegate中添加全局属性持有windowController的引用,修正后的AppDelegate代码如下:

// AppDelegate.swift
import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {
    // 新增属性持有windowController,避免被自动释放
    var mainWindowController: NSWindowController?

    func applicationDidFinishLaunching(_ aNotification: Notification) {
        let storyboard = NSStoryboard(name: "Main", bundle: nil)
        if let windowController = storyboard.instantiateController(withIdentifier: "mainWindow") as? NSWindowController {
            // 赋值给全局属性持有
            self.mainWindowController = windowController
            
            windowController.window?.level = .floating
            guard let mainScreen = NSScreen.screens.first else { return }
            let targetFrame = mainScreen.visibleFrame
            let windowSize = windowController.window?.frame.size ?? .zero
            let targetOrigin = NSPoint(
                x: targetFrame.midX - windowSize.width / 2,
                y: targetFrame.midY - windowSize.height / 2
            )
            windowController.window?.setFrameOrigin(targetOrigin)
            
            windowController.window?.zoom(self)
            windowController.window?.backgroundColor = .white
            windowController.window?.isMovable = false
            windowController.window?.styleMask.remove(.resizable)
            windowController.showWindow(self)
        } else {
            print("failed to show the window")
        }
    }
}

修改后即可在ViewController中通过self.view.window?.setIsVisible()正常控制窗口显隐。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:57:02