macOS应用开发如何隐藏全屏窗口的顶部标题栏分割线
问题描述
我遇到的问题是macOS应用全屏模式下的窗口头部栏显示问题。
当我将光标移动到屏幕顶部时,显示效果如下:
但我想要实现的无顶部横线效果如下:
隐藏窗口控制按钮的实现不存在难度,可通过如下代码完成:
wnd.standardWindowButton(NSWindow.ButtonType.closeButton)?.isHidden = true wnd.standardWindowButton(NSWindow.ButtonType.miniaturizeButton)?.isHidden = true wnd.standardWindowButton(NSWindow.ButtonType.zoomButton)?.isHidden = true
但无法隐藏头部的那条分割线,检索相关技术资料未找到对应解决方案,猜测是否存在需要通过特殊方式禁用的额外“安全区域”?
已尝试方案
- SwiftUI实现方案:
WindowGroup { SomeView() .edgesIgnoringSafeArea(.top) } .windowStyle( HiddenTitleBarWindowStyle() )
该方案仅能隐藏窗口化模式下的标题栏,对全屏模式下的头部横线无效。
- AppKit接口修改NSWindow属性方案:
NSApp?.mainWindow?.styleMask.insert(NSWindow.StyleMask.unifiedTitleAndToolbar) NSApp?.mainWindow?.styleMask.insert(NSWindow.StyleMask.fullSizeContentView) NSApp?.mainWindow?.styleMask.insert(NSWindow.StyleMask.titled) NSApp?.mainWindow?.toolbar?.isVisible = false NSApp?.mainWindow?.titleVisibility = .hidden NSApp?.mainWindow?.titlebarAppearsTransparent = true
上述代码同样无法去除全屏模式下的窗口头部横线。
解决方案
全屏模式下的顶部横线是macOS为全屏窗口单独渲染的标题栏分割线,常规的标题栏隐藏、透明属性只作用于窗口化状态,不会同步到全屏场景,核心需要做两步处理:一是关闭工具栏的基线分割线开关,二是在窗口进入全屏后遍历视图层级找到系统自动生成的分割线视图手动隐藏,两种常用场景的实现代码如下:
纯AppKit项目
首先在窗口初始化时配置基础属性:
// 基础标题栏配置 wnd.titleVisibility = .hidden wnd.titlebarAppearsTransparent = true wnd.toolbar?.isVisible = false // 关键:关闭工具栏默认的基线分割线 wnd.toolbar?.showsBaselineSeparator = false wnd.styleMask.insert([.fullSizeContentView, .unifiedTitleAndToolbar])
之后监听窗口进入全屏的系统通知,在回调里隐藏分割线:
NotificationCenter.default.addObserver( forName: NSWindow.didEnterFullScreenNotification, object: nil, queue: .main ) { notification in guard let window = notification.object as? NSWindow else { return } // 递归遍历视图层级查找系统分割线 func locateDivider(in view: NSView) -> NSView? { for subview in view.subviews { // 系统分割线视图的类名固定包含"divider"字段 if NSStringFromClass(type(of: subview)).lowercased().contains("divider") { return subview } if let target = locateDivider(in: subview) { return target } } return nil } // 从标题栏根视图开始查找 let searchRoot = window.standardWindowButton(.closeButton)?.superview?.superview ?? window.contentView?.superview ?? window.contentView locateDivider(in: searchRoot)?.isHidden = true }
SwiftUI项目
纯SwiftUI生命周期的项目可以通过视图修饰符注入上述逻辑,不需要额外创建NSWindowDelegate:
struct FullScreenNoDividerModifier: ViewModifier { func body(content: Content) -> some View { content .edgesIgnoringSafeArea(.top) .onAppear { guard let mainWindow = NSApp.windows.first(where: \.isMainWindow) else { return } // 基础窗口配置 mainWindow.titleVisibility = .hidden mainWindow.titlebarAppearsTransparent = true mainWindow.toolbar?.showsBaselineSeparator = false // 监听全屏事件 NotificationCenter.default.addObserver( forName: NSWindow.didEnterFullScreenNotification, object: mainWindow, queue: .main ) { _ in func locateDivider(in view: NSView) -> NSView? { for subview in view.subviews { if NSStringFromClass(type(of: subview)).lowercased().contains("divider") { return subview } if let target = locateDivider(in: subview) { return target } } return nil } let searchRoot = mainWindow.contentView?.superview ?? mainWindow.contentView locateDivider(in: searchRoot)?.isHidden = true } } } } // 调用示例 @main struct YourApp: App { var body: some Scene { WindowGroup { ContentView() .modifier(FullScreenNoDividerModifier()) } .windowStyle(.hiddenTitleBar) } }
注意:不要在窗口未进入全屏时修改分割线的hidden属性,系统在窗口切换布局状态(窗口化/全屏/分屏)时会重建标题栏视图,只需要在
didEnterFullScreenNotification回调中执行隐藏逻辑即可,该方案兼容macOS 12.0及以上所有正式版本。
内容的提问来源于stack exchange,提问作者Andrew
相关产品推荐
相关产品推荐

