- macOS Swift 原生项目集成 Python3 运转环境
最近想开发一个根据 Menu Bar 的项目,然后把 NSWindowController 作为内容展示和交互。看到很多的教程都是在 Menu Bar 上添加 NSPopover,然后合作 NSViewController 作业,这个计划会在 Menu Bar 下显现 NSPopover 的箭头,不符合我的需求,我想要的效果是 macOS 系统调理音量、挑选输入法这种相似的窗口。
一、新建一个 Menu Bar 的 macOS 项目
打开 Main.storyboard,删去 WindowController 和 ViewController
在 info 中添加一个配置 Application is agent (UIElement),设置为 YES
二、创立 NSStatusItem
拖入 Menu Bar 的 icon,新建 StatusBarMenu 文件,代码如下
import AppKit
class StatusBarMenu: NSObject {
var statusBarItem: NSStatusItem!
override init() {
super.init()
initStatusBarItem()
}
// 初始化状态栏Button
func initStatusBarItem() {
self.statusBarItem = NSStatusBar.system.statusItem(withLength: CGFloat(NSStatusItem.squareLength))
if let button = self.statusBarItem.button {
button.image = NSImage(named: "menubar")
button.image?.size = NSSize(width: 18.0, height: 18.0)
button.image?.isTemplate = true
button.action = #selector(AppDelegate.instance.togglePop)
button.sendAction(on: [.leftMouseUp, .rightMouseUp])
}
}
}
三、AppDelegate 中去运用 NSStatusItem
// 声明特点
static private(set) var instance: AppDelegate! = nil
var statusMenu: StatusBarMenu?
var showPopWindow = false // 记录是否显现主窗口
func applicationDidFinishLaunching(_ aNotification: Notification) {
AppDelegate.instance = self
self.statusMenu = StatusBarMenu()
}
// MARK: 显现和躲藏窗口
@objc func togglePop() {
}
现在运转项目,能够在顶部菜单栏看到 Menu Bar 的 icon 了。
四、创立主窗口 PopWindowController
在 PopWindowController.xib 中拖入 Visual Effect View
Window 设置
import Cocoa
class PopWindowController: NSWindowController {
override var windowNibName: NSNib.Name {
return NSNib.Name("PopWindowController")
}
override func windowDidLoad() {
super.windowDidLoad()
}
}
回到 AppDelegate 中运用 PopWindowController
// 声明特点
lazy var popWindowController = PopWindowController()
@objc func togglePop() {
if !showPopWindow {
// 计算窗口的方位
if let event = NSApp.currentEvent, let window = event.window, let popWindow = popWindowController.window {
let eventFrame = window.frame
let eventOrigin = eventFrame.origin
let popWindowTopLeftPosition = CGPoint(x: eventOrigin.x, y: eventOrigin.y)
popWindow.setFrameTopLeftPoint(popWindowTopLeftPosition)
popWindow.makeKeyAndOrderFront(self)
NSApp.activate(ignoringOtherApps: true)
showPopWindow = true
}
} else {
if let popWindow = popWindowController.window {
popWindow.orderOut(nil)
showPopWindow = false
}
}
}
这个时候运转,能够看到窗口已经出现,但是窗口是可拖动的,这显着不合适的。 处理办法是在 PopWindowController 中设置窗口不可移动。
import Cocoa
class PopWindowController: NSWindowController {
override var windowNibName: NSNib.Name {
return NSNib.Name("PopWindowController")
}
override func windowDidLoad() {
super.windowDidLoad()
// 窗口不可移动
window?.isMovable = false
}
}
五、监控鼠标点击其他 Menu Bar
到目前为止,全体效果已经实现。点击菜单栏其他的图标时,我们的窗口没有消失,这个问题需要处理。
新增两个通知,当点击其他菜单时,调用窗口的躲藏办法即可。
func applicationDidFinishLaunching(_ aNotification: Notification) {
AppDelegate.instance = self
self.statusMenu = StatusBarMenu()
NotificationCenter.default.addObserver(forName: NSWindow.didResignKeyNotification, object: nil, queue: OperationQueue.main) { _ in
self.togglePop()
}
NotificationCenter.default.addObserver(forName: NSWindow.didResignMainNotification, object: nil, queue: OperationQueue.main) { _ in
self.togglePop()
}
}
完好 demo 下载