NSWindow 无标题栏窗口无法获得焦点与 resize 鼠标指示的解决办法

NSWindow 无标题栏窗口无法获得焦点与 resize 鼠标指示的解决办法

Base on macOS 10.15, Xcode 11.7.

在 macOS 程序中,对 NSWindow 实例可以通过删除 NSWindow.StyleMask.titled 属性来设置窗口为无标题栏窗口。

// 方法一:实例化时通过 styleMask 实参数组设置,不包括 .titled 即无标题栏
window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.resizable],
            backing: .buffered, defer: false)

// 方法二:或者在后面通过 remove 掉该属性也行
window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered, defer: false)
window.styleMask.remove(.titled)

但是无标题栏的窗口,其 NSWindow.canBecomeKey 属性会变成 false。Key window 的意思,就是指可以接收 keyboard 事件的窗口,所以如果一个 NSWindow 的 canBecomeKey 属性为 false,就说明它不能接收键盘事件,即无法获得输入焦点。同时如果鼠标放在窗口的边框上,也不会出现缩放窗口的指示,虽然我上面定义了 resizable,窗口也确实是可以缩放,但就是没有指示出来。如下图所示:

而且,NSWindow.canBecomeKey 是一个只读的计算属性,由系统自动计算。按 apple 官方文档的说法,如果一个窗口有 title bar 或者 resize bar,那么该属性就会是 true。但实际上,只要没有了 title bar,即使我定义了 resizable,该属性也是 false。这到底是系统的 BUG 还是文档乱写的啊。 (╯▔皿▔)╯

为了想要实现无标题栏的窗口还能获得输入焦点,并且能显示这个 resize indicator。那么我们就不得不定义一个 NSWindow 的子类,并override canBecomeKey 计算属性:

import SwiftUI

class MyWindow: NSWindow {
    override var canBecomeKey: Bool {
        return true
    }
}

然后用这个子类来实例化一个无标题栏窗口即可。

 

思考🤔

是不是其实无标题栏窗口,应该用 NSPanel 来实现更好点啊?跟NSWindow 有啥区别。后面试试

Leave a Reply

Your email address will not be published. Required fields are marked *