不知道大家有没有用过菜单栏形式的状态栏工具,类似于之前写的 NSPopover 的工具在系统顶栏占用一个图标,不同的是点击之后弹出的不是弹窗而是一个菜单,就像下面截图展示的工具,本文就讲一下如何实现。



android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单


平台

  • macOS 10.15
  • Xcode 11.1
  • Swift 5.1

本文使用上述平台实现验证,版本不同可能有些差异,但基本思路一致。

工程新建及配置

  • 打开xcode新建工程, macOS -> App -> Next:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_02


  • 输入工程名称:MenuToolDemolanguage 选择SwiftUser Interface 选择 SwiftUI(本文不会用到 SwiftUI)点击 Next:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_02


  • 选择合适的目录,点击 create
  • 点击运行按钮,可以看到程序运行,出现一个显示 hello world
  • 工程导航栏选中工程MenuToolDemo,打开Info标签页;
  • 可以看到Custom macOS application Target Properties组,添加新的配置Application is agent(UI Element),布尔属性,值为 YES:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_04


  • 重新运行程序,可以看到已经不显示Dock图标;
  • ContentView.swift
  • 打开文件AppDelegate.swift,删掉两个地方代码:
var window: NSWindow!

// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()

// Create the window and set the content view.
window = NSWindow(
    contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
    styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
    backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)


  • 再次运行程序,主窗口也不显示了,连菜单栏也木有了,不要着急,咱继续。

添加状态栏按钮

打开文件AppDelegate.swift,在类中添加属性,这一步是创建一个状态栏按钮,设置宽度属性NSStatusItem.squareLength,代码如下:


let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)


状态栏按钮总该需要一个图标吧!打开Assets.xcassets,右击显示AppIcon下方的空白区,选择New Image Set,重命名为statusIcon,当然这个名字随便定,选中这个图集,会看到右侧有配置区,配置图集按照Template Image渲染。

看到有三个虚线框空白区,这就是图片区,状态栏按钮的图片基本大小为


,还需2倍和3倍的适用于视网膜屏幕的mac,像素分别是



,可以使用以下我提供的图标:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_05


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_06


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_07


分别将图拖到对应位置:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_08


找到applicationDidFinishLaunching在其中添加以下代码,为状态栏按钮配置图标和行为:


if let button = statusItem.button {
    button.image = NSImage(named: "StatusIcon")
}


此时运行程序会看到状态栏中出现了我们定义的按钮,当然此时鼠标单击没有任何动作发生。

前面设置图片集渲染方式为 Template Image,是为了适配不同的状态栏主题,因为macOS还有个暗黑主题不是?

两种主题下的效果如下:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_09


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_10


添加菜单

打开 Main.storyboard

  • 按下快捷键 Command + Shift + L
  • 点击 Xcode 窗口右上角的 ➕ 按钮

在搜索框中输入 Menu,就会检索到 NSMenu 控件:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_11


鼠标左键在控件单击不松拖放到文件 Main.storyboard 的左边栏 First Responder


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_12


按下快捷键 Ctrl + Option + Command + Enter(⌃⌥⌘⏎) 打开 Assitant


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_13


按住 Ctrl 键,鼠标左键按住 Menu 控件不松拖动至辅助编辑器的文件 AppDelegate.swift 中,在弹出的属性添加弹窗中输入属性名 menu,点击 Connect 就会看到 AppDelegate.swift


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_14

https://www.zhihu.com/video/1170069061483552768


打开文件 AppDelegate.swift ,在上面配置按钮图标的代码上面添加以下代码:


statusItem.menu = menu


运行程序,鼠标左键和右键单击菜单栏按钮都会弹出我们添加的按钮,包含 item1、item2 和 item3。

配置菜单

下面我们看一下菜单即菜单项的基本使用。

菜单项基本属性

打开文件 main.storyboard,单击 menu,选中 Item1,可以在右侧属性检查器(Attributes Inspector) 中看到各个属性。选中 Item2 和 Item3,按 Delete 键删除,选中 Item1

名称 - Title

修改 Item1 的属性检查器的 Title ,比如修改成 退出,就会修改此菜单项现实的名称。

状态 - State

State 表示选中状态(check),三种状态:on、off、mixed。当设置为 on 的时候会看到菜单项前出现一个对号,这里设置为 off

图标 - Image

可以设置通用的图标 Image,同时也可以设置各种状态的图标。这里我们只设置 ImageNSStopProgressFreestandingTemplate,编译运行:


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_15


行为 - Action

你会好奇为什么上面运行 退出 是灰色的,那是因为我们还没为它指定行为,类似于前面绑定 menu 属性的操作,同样的操作,只不过这次是按住 Ctrl 键的同时,鼠标左键单击 退出 菜单项不松拖动到辅助编辑器的 AppDelegate.swift 文件中,绑定一个名叫 quitApp 的 action。

实现 action 的功能为退出应用,最终 quitApp 方法如下:


@IBAction func quitApp(_ sender: Any) {
    NSApplication.shared.terminate(self)
}


编译运行程序,单击菜单栏的按钮可以看到 退出

快捷键

每个菜单项执行行为可以绑定快捷键的,就是设置在属性检查起中的 Key Equivalent 属性,我们这里设置为 Q,运行程序,可以看到菜单项名称后面多了一个 Q,当显示菜单时按下 Q 键,等同于点击了 退出

多级菜单

多级菜单也很容易实现。

  • 添加新的菜单项
    打开文件 main.storyboard ,按下快捷键 Command + Shift + L ,在控件库弹窗输入 Menu item,拖动控件 Menu Item退出
  • 威刚添加的菜单项添加菜单
    打开控件库弹窗,拖动 Menu

运行程序,点击菜单栏按钮,鼠标放到菜单项 Item


android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_16


总结

本文简单讲了菜单形式菜单栏工具的基本实现,推一反三便可以实现更丰富的小工具了。最终实现的工程文件已经打包在下面:

MenuToolDemopichome-1254392422.cos.ap-chengdu.myqcloud.com


博客原文:

macOS 开发之菜单栏形式的状态栏小工具

android 状态栏快捷菜单 android菜单栏实现_android 状态栏快捷菜单_17