文章包含以下内容
- 窗口操作
- 如何拦截用户的窗口关闭操作
- 如何用隐藏代替关闭窗口
- 如何用窗口退出显示队列代替关闭
- 如何窗口关闭后icon保持在Dock栏
- 如何在关闭窗口时彻底杀死程序
- 如何重新打开已关闭的窗口
- 窗口外观
- 大小
- 颜色
窗口操作
1、如何拦截用户的窗口关闭操作?
首先我们要知道,在用户点击窗口左上角x关闭窗口时,系统首先调用的是
func windowShouldClose(_ sender: NSWindow) -> Bool
这个方法。该方法默认返回true,即点击关闭就销毁窗口。
我们在重写该方法,即可修改用户行为。
extension AppDelegate: NSWindowDelegate {
func windowShouldClose(_ sender: NSWindow) -> Bool {
NSApp.hide(nil)
return false
}
}
NSApp.hide(nil)将关闭行为修改为了隐藏窗口行为。
在使用该方法前,记得在func applicationDidFinishLaunching中,将window.delegate = self,这样才可以生效。
2、如何用窗口退出显示队列代替关闭?
既然方法1已经解决问题了,为什么还需要方法2呢?
方法1有个硬伤,如果使用hide代替close,在提审App Store时,会审核不通过,原因是:
Specifically, when closing the Main Window, the app stays open, however the App Menu disappears.
大家可以试一下,如果使用方法1,在用户关闭窗口时,左上角你的应用名会马上消失
但苹果的要求是需要关闭窗口后,仍然保留上方的menu,直到用户点击其他窗口。
要解决这个问题,我们就需要用到方法2:
extension AppDelegate:NSWindowDelegate {
func windowShouldClose(_ sender: NSWindow) -> Bool {
sender.orderOut(self)
return false
}
}
与方法1类似,只是把hide(nil)替换为sender.orderOut(self),orderOut方法是将窗口移除显示队列,其实与hide效果类似,但是它仍然能保证menu存在。
3、如何窗口关闭后icon保持在Dock栏
我们会发现,有些应用如Foxmail在点击关闭窗口后,仍然会保留在Dock中。
但是,有些应用关闭后马上就从Dock上消失了。
其区别就在于Plist(info.list)中的配置:
最后一行,如果是Yes的话,则点击关闭后就不再出现在Dock中;No则会保留,并且有个小点指示器显示正在运行。
4、isReleasedWhenClosed
window?.isReleasedWhenClosed = false是一个很强大的语句。一般情况下,我们点击左上角关闭窗口,并且没有重写windowShouldClose这个方法,那么在关闭后,window这个对象就会把系统释放资源了。
但是,如果我们将isReleasedWhenClosed设为false,则窗口对象不会被销毁,我们随时可以调用其他方法将窗口重新显示出来。
5、如何点击Dock重新打开已关闭的窗口
func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
if !flag {
for window: AnyObject in sender.windows {
if window.frameAutosaveName == "Main Window" {
window.makeKeyAndOrderFront(self)
}
}
return true
}
return true
}
我们需要重写AppDelegate中的applicationShouldHandleReopen方法,将对应的窗口放置回窗口队列的最前端。
如果isReleasedWhenClosed 没有设置为 false,则窗口对象已经被销毁,此时applicationShouldHandleReopen方法不会为你新建该window,表现出来就是点击Dock没反应。
6、如何在关闭窗口时强制杀死程序
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
return true会让程序的最后一个窗口关闭时,完全杀死程序所有进程,这能确保你的程序不会再出现在Dock中。(除非你将程序固定在Dock)
设置默认窗口大小
窗口大小的设置主要在AppDelegate.swift中配置
1、通过windows.setFrame方法设置窗口大小
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
// Add `@Environment(.managedObjectContext)` in the views that will need the context.
let contentView = ContentView().environment(.managedObjectContext, persistentContainer.viewContext).frame(minWidth: 450, maxWidth: .infinity, minHeight: 400, maxHeight: .infinity)
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.setFrame(CGRect(x: 10, y: 10, width: 550, height: 650), display: true)
window.center()
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
}
2、设置窗口最小尺寸
macos中,窗体的大小是由内容的大小决定的,所以我们只需设置内容的最小尺寸,就相当于设置了窗口的最小尺寸
let contentView = ContentView().environment(.managedObjectContext, persistentContainer.viewContext).frame(minWidth: 450, maxWidth: .infinity, minHeight: 400, maxHeight: .infinity)
3、设置窗口颜色
window.backgroundColor = NSColor.white