如何创建可被系统工具识别的无圆角纯无边框macOS窗口
在macOS上创建可被桌面管理工具识别的纯无边框窗口
在macOS中,将window.styleMask设为[]或[.closable, .miniaturizable, .resizable, .fullSizeContentView]可实现纯无边框窗口,但这类窗口无法被Magnet、Moom等桌面管理工具识别;若保留.titled样式,工具可识别窗口,但窗口会自带圆角,不符合需求。以下是两种解决思路:
方案1:保留.titled样式,彻底去除窗口圆角
这种方式无需修改Accessibility属性,直接调整窗口配置去掉圆角,同时保持桌面工具的识别能力。
修改后的AppDelegate代码:
class AppDelegate: NSObject, NSApplicationDelegate { private lazy var window: NSWindow = NSWindow() func applicationDidFinishLaunching(_ aNotification: Notification) { // 保留.titled样式以支持桌面工具识别 window.styleMask = [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView] window.backingType = .buffered window.isReleasedWhenClosed = false window.center() window.setFrameAutosaveName("Main Window") window.title = "Window" window.isMovableByWindowBackground = true // 隐藏标题栏相关元素 window.titleVisibility = .hidden window.titlebarAppearsTransparent = true window.standardWindowButton(.closeButton)?.isHidden = true window.standardWindowButton(.miniaturizeButton)?.isHidden = true window.standardWindowButton(.zoomButton)?.isHidden = true // 关键:设置窗口圆角为0,彻底去除圆角 window.cornerRadius = 0 // 确保内容视图无额外圆角 window.contentView?.wantsLayer = true window.contentView?.layer?.cornerRadius = 0 window.contentView = NSHostingView(rootView: ContentView()) window.makeKeyAndOrderFront(window) } }
若上述设置仍有圆角残留,可自定义NSWindow子类强制去除圆角:
class BorderlessWindow: NSWindow { override func draw(_ dirtyRect: NSRect) { super.draw(dirtyRect) // 强制绘制无圆角的窗口背景 NSColor.white.setFill() dirtyRect.fill() } override var canBecomeKey: Bool { return true } override var canBecomeMain: Bool { return true } }
将AppDelegate中的window改为BorderlessWindow实例即可。
方案2:无.titled样式,通过Accessibility伪装让桌面工具识别
该方案保留纯无边框样式,通过重写窗口的Accessibility属性,让桌面管理工具误以为窗口包含.titled样式。
首先定义自定义窗口类并扩展Accessibility方法:
class CustomWindow: NSWindow { override var canBecomeKey: Bool { return true } override var canBecomeMain: Bool { return true } } extension CustomWindow { // 重写Accessibility属性,返回包含.titled的样式掩码 override func accessibilityAttributeValue(_ attribute: NSAccessibility.Attribute) -> Any? { if attribute == .windowStyleMask { // 实际styleMask不含.titled,但返回给Accessibility的包含 let actualMask = self.styleMask let maskedWithTitled = actualMask.union(.titled) return maskedWithTitled.rawValue } return super.accessibilityAttributeValue(attribute) } // 确保Accessibility属性不可修改(部分工具会检查) override func accessibilityIsAttributeSettable(_ attribute: NSAccessibility.Attribute) -> Bool { if attribute == .windowStyleMask { return false } return super.accessibilityIsAttributeSettable(attribute) } }
对应的AppDelegate代码:
class AppDelegate: NSObject, NSApplicationDelegate { private lazy var window: CustomWindow = CustomWindow() func applicationDidFinishLaunching(_ aNotification: Notification) { // 保持纯无边框的样式掩码 window.styleMask = [.closable, .miniaturizable, .resizable, .fullSizeContentView] window.backingType = .buffered window.isReleasedWhenClosed = false window.center() window.setFrameAutosaveName("Main Window") window.title = "Window" window.isMovableByWindowBackground = true window.contentView = NSHostingView(rootView: ContentView()) window.makeKeyAndOrderFront(window) } }
注意事项
- 方案2依赖桌面工具通过Accessibility读取窗口属性,部分工具可能采用其他检测方式,需测试验证;
- 确保
ContentView的ignoresSafeArea()设置正确,避免内容被窗口边缘裁剪; - 测试环境为macOS 12.7.6、Xcode 14.2,最低部署目标12.0,若系统版本不同可能需调整API。
内容的提问来源于stack exchange,提问作者Mango
相关产品推荐
相关产品推荐

