Mac Catalyst实现NSToolbar透明并保留信号灯按钮调整能力
Mac Catalyst 实现透明NSToolbar并保留标题栏工具栏控制
一、实现透明NSToolbar + 保留UITitlebarToolbarStyle调整信号灯
要同时满足透明工具栏和通过UITitlebarToolbarStyle调整信号灯位置,可结合标题栏配置与工具栏私有视图调整(这类视图调整在Mac Catalyst中通常可通过审核):
- 配置窗口标题栏基础属性
在UISceneDelegate的scene(_:willConnectTo:options:)方法中,设置标题栏透明、隐藏标题并绑定自定义工具栏:
guard let windowScene = scene as? UIWindowScene else { return } // 启用工具栏样式控制,调整信号灯位置 windowScene.titlebar?.toolbarStyle = .unifiedCompact // 可选.unified/.automatic等 windowScene.titlebar?.titleVisibility = .hidden windowScene.titlebar?.backgroundColor = .clear // 创建并绑定工具栏 let mainToolbar = NSToolbar(identifier: "MainToolbar") mainToolbar.delegate = self mainToolbar.displayMode = .iconOnly mainToolbar.isVisible = true windowScene.titlebar?.toolbar = mainToolbar
- 设置工具栏透明
通过访问工具栏私有视图_toolbarView来设置透明背景:
if let toolbarView = mainToolbar.value(forKey: "_toolbarView") as? NSView { toolbarView.wantsLayer = true toolbarView.layer?.backgroundColor = NSColor.clear.cgColor // 隐藏默认分隔线 toolbarView.subviews.forEach { if $0.className.contains("NSToolbarSeparatorView") { $0.isHidden = true } } }
- 添加工具栏按钮(如完成按钮)
通过NSToolbarDelegate协议实现自定义按钮:
extension YourSceneDelegate: NSToolbarDelegate { func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { return [.init("DoneButton")] } func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { return [.init("DoneButton")] } func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { guard itemIdentifier == .init("DoneButton") else { return nil } let doneItem = NSToolbarItem(itemIdentifier: itemIdentifier) doneItem.label = "完成" doneItem.image = NSImage(systemSymbolName: "checkmark", accessibilityDescription: "完成") doneItem.target = self doneItem.action = #selector(onDoneTapped) return doneItem } @objc private func onDoneTapped() { // 处理按钮逻辑 } }
配置完成后,工具栏保持透明,toolbarStyle设置依然生效,可正常调整信号灯位置。
二、类似Electron 8的信号灯按钮调整功能实现
原生Mac Catalyst/Swift没有直接提供像Electron那样自由调整信号灯位置的API,但可通过两种方式实现类似效果:
1. 间接调整信号灯与工具栏间距
若仅需拉开信号灯与工具栏内容的距离,可在工具栏最左侧添加弹性空间项:
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { return [.flexibleSpace, .init("DoneButton")] }
工具栏内容会被挤到右侧,信号灯与按钮间自动留出空隙,实现相对位置调整。
2. 自定义信号灯(复杂方案)
若需完全自定义信号灯位置(如移到窗口中间或右侧),需隐藏系统标题栏,自行绘制控制按钮并模拟系统行为:
- 隐藏系统标题栏:
windowScene.titlebar?.isHidden = true - 自定义最小化、最大化、关闭按钮,添加到窗口顶部
- 通过
NSWindow的performMiniaturize(_:)、performZoom(_:)、performClose(_:)方法模拟系统窗口操作 - 监听鼠标事件实现窗口拖拽:
NSEvent.addLocalMonitorForEvents(matching: .leftMouseDown) { event in guard let window = self.windowScene?.windows.first else { return event } window.performDrag(with: event) return event }
该方案需处理大量系统交互细节,适合高度自定义需求,但开发成本较高。
内容的提问来源于stack exchange,提问作者Bluebyte
相关产品推荐
相关产品推荐

