由于这个问题最近受到了更多的关注,而且唯一的回答没有完全解决问题,我想重复我的问题的编辑部分,并将其标记为已解决。
编辑2:添加了一个额外的代码片段,允许使用SwiftUI视图作为状态栏图标。对于显示动态徽章可能很方便。
找到了一种在swiftui中显示它的方法,而不需要烦人的NSPopover
。即使我使用了AppDelegate的applicationDidFinishLaunching
来执行代码,它也可以从任何地方调用您的应用程序,甚至在SwiftUI生命周期应用程序中。
以下是代码:
func applicationDidFinishLaunching(_ aNotification: Notification) {
// SwiftUI content view & a hosting view
// Don't forget to set the frame, otherwise it won't be shown.
//
let contentViewSwiftUI = VStack {
Color.blue
Text("Test Text")
Color.white
}
let contentView = NSHostingView(rootView: contentViewSwiftUI)
contentView.frame = NSRect(x: 0, y: 0, width: 200, height: 200)
// Status bar icon SwiftUI view & a hosting view.
//
let iconSwiftUI = ZStack(alignment:.center) {
Rectangle()
.fill(Color.green)
.cornerRadius(5)
.padding(2)
Text("3")
.background(
Circle()
.fill(Color.blue)
.frame(width: 15, height: 15)
)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottomTrailing)
.padding(.trailing, 5)
}
let iconView = NSHostingView(rootView: iconSwiftUI)
iconView.frame = NSRect(x: 0, y: 0, width: 40, height: 22)
// Creating a menu item & the menu to add them later into the status bar
//
let menuItem = NSMenuItem()
menuItem.view = contentView
let menu = NSMenu()
menu.addItem(menuItem)
// Adding content view to the status bar
//
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
statusItem.menu = menu
// Adding the status bar icon
//
statusItem.button?.addSubview(iconView)
statusItem.button?.frame = iconView.frame
// StatusItem is stored as a property.
self.statusItem = statusItem
}
MenuBarExtra
(macOS Ventura)在 macOS 13.0+ 和 Xcode 14.0+ 中,MenuBarExtra 结构体允许您创建一个类似于 NSStatusBar 图标和菜单的系统菜单栏。当您想要提供对常用功能的访问,即使您的应用程序不活动时,可以使用 MenuBarExtra
。
import SwiftUI
@available(macOS 13.0, *) // macOS Ventura
@main struct StatusBarApp: App {
@State private var command: String = "a"
var body: some Scene {
MenuBarExtra(command, systemImage: "\(command).circle") {
Button("Uno") { command = "a" }
.keyboardShortcut("U")
Button("Dos") { command = "b" }
.keyboardShortcut("D")
Divider()
Button("Salir") { NSApplication.shared.terminate(nil) }
.keyboardShortcut("S")
}
}
}
在 Xcode 的 Info
选项卡中,选择 Application is agent (UIElement)
并将其值设置为 YES
。
或者您可以通过编程的方式隐藏应用程序的图标programmatically。
MenuBarExtra
设置最大帧?我已经尝试使用 defaultSize
修饰符,但似乎它不起作用。 - jackson89NSApp.activate(ignoringOtherApps: true)
和 appWindow?.makeKeyAndOrderFront(nil)
。 - Pavel Lobodinský// Create the status item in the Menu bar
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
// Add a menu and a menu item
let menu = NSMenu()
let editMenuItem = NSMenuItem()
editMenuItem.title = "Edit"
menu.addItem(editMenuItem)
//Set the menu
self.statusBarItem.menu = menu
//This is the button which appears in the Status bar
if let button = self.statusBarItem.button {
button.title = "Here"
}
这将在你的菜单栏中添加一个带有自定义菜单的按钮。
编辑 - 如何使用 SwiftUI 视图
如您所询问,以下是如何使用 SwiftUI 视图的答案。
首先创建一个 NSPopover,然后将您的 SwiftUI 视图包装在 NSHostingController
中。
var popover: NSPopover
let popover = NSPopover()
popover.contentSize = NSSize(width: 350, height: 350)
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: contentView)
self.popover = popover
然后,不再显示NSMenu,而是切换到弹出窗口:
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
if let button = self.statusBarItem.button {
button.title = "Click"
button.action = #selector(showPopover(_:))
}
以下是需要执行的操作:
@objc func showPopover(_ sender: AnyObject?) {
if let button = self.statusBarItem.button
{
if self.popover.isShown {
self.popover.performClose(sender)
} else {
self.popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
}
}
}