macOS的menuBar功能非常強大,我們在開發macOS應用的時候,經常需要利用menuBar實現功能。這篇文章主要是關於如何用swiftUI優雅地現在menuBar的popover。
最終效果圖:
創建Popover
在AppDelegate文件中,聲明一個NSPopover變量(下面的statusBarItem之後會用到)
var popover: NSPopover! var statusBarItem: NSStatusItem!
隨後,在applicationDidFinishLaunching中, ContentView 初始化之後,加上
// Create the popover
let popover = NSPopover()
popover.contentSize = NSSize(width: 400, height: 400)
popover.behavior = .transient //代表用戶點擊其他區域時popover自動消失 popover.contentViewController = NSHostingController(rootView: contentView) self.popover = popover
此時我們的AppDelegate文件應該長這樣:
import Cocoa
import SwiftUI
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var popover: NSPopover!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Create the popover
let popover = NSPopover()
popover.contentSize = NSSize(width: 400, height: 500)
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: contentView)
self.popover = popover
}
}
這樣我們即創建了一個Popover視圖以及它的控制器,這個Popover的視圖內容是我們的ContentView.swift裏的內容。這樣我們就可以在ContentView裏用SwiftUI自由地定製我們的Popover。接下來我們要做的是,創建一個menuBarItem,當用戶點擊menuBarItem的按鈕時,彈出我們已經寫好的Popover。
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
if let button = self.statusBarItem.button {
button.image = NSImage(named: "Icon")
button.action = #selector(togglePopover(_:))
}
還記得我們一開始聲明瞭
var statusBarItem: NSStatusItem!
現在我們需要創建它,同時給它在menuBar設置個圖標,綁定點擊事件爲togglePopover
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
if let button = self.statusBarItem.button {
statusBarItem.button?.title = "⏳"
button.action = #selector(togglePopover(_:))
}
綁定togglePopover是爲了在用戶點擊時彈出Popover
// Create the status item
@objc func togglePopover(_ 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)
}
}
}
最終,我們的AppDelegate文件長這樣
import Cocoa
import SwiftUI
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var popover: NSPopover!
var statusBarItem: NSStatusItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Create the popover
let popover = NSPopover()
popover.contentSize = NSSize(width: 400, height: 500)
popover.behavior = .transient
popover.contentViewController = NSHostingController(rootView: contentView)
self.popover = popover
// Create the status item
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.variableLength))
if let button = self.statusBarItem.button {
statusBarItem.button?.title = "⏳"
button.action = #selector(togglePopover(_:))
}
}
@objc func togglePopover(_ 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)
}
}
}
}