告别简陋读数与复杂仪表:纯Swift手搓原生macOS毛玻璃系统监控

在 macOS 上监控系统资源,你大概只有两种选择:要么忍受菜单栏里那几个干巴巴的数字,想看详细数据时根本无处下手;要么打开一个像飞机驾驶舱一样的巨大仪表盘,满屏图表直接把你淹没。

有没有一种可能,既能享受菜单栏的轻便,又能在需要时优雅地展开一块漂亮的详情面板?

这就是 SysMonitor 想要解决的问题。它是一个完全开源的 macOS 原生菜单栏应用,用 100% Swift 和 SwiftUI 写成,没有 Electron,没有奇怪的外壳,干净到骨子里。

痛点:原生下拉框实现不了毛玻璃

做菜单栏应用时,苹果官方推荐用 NSPopover 来做下拉窗口。它确实省心,能自动处理箭头和定位,但问题是——管得太宽。

它的边框、背景、圆角都是定死的,很难做出现在流行的“毛玻璃(Glassmorphism)”效果,也做不到内容区域和桌面背景的通透融合。

作者的做法是:扔掉 NSPopover,从零手搓一个无边框的 NSWindow,然后在里面塞入 NSVisualEffectView

// 创建一个无边框、全透明的窗口
window.titlebarAppearsTransparent = true
window.titleVisibility = .hidden
window.isOpaque = false
window.backgroundColor = .clear

// 添加毛玻璃质感的背景层
let visualEffect = NSVisualEffectView()
visualEffect.blendingMode = .behindWindow  // 混合模式:显示在窗口内容后方
visualEffect.material = .hudWindow       // 使用类似系统 HUD 的材质
visualEffect.state = .active             // 激活视觉效果
visualEffect.autoresizingMask = [.width, .height] // 跟随窗口自动调整大小

这样一来,窗口就像一块悬浮在桌面上的磨砂玻璃,视觉上和原生系统风格完全统一。

难题:窗口该出现在哪里?

不用 NSPopover 的代价是:系统不会再帮你把窗口“挂”在菜单栏图标下方。窗口像个没头苍蝇,根本不知道图标在哪。

解决办法就是拿起“草稿纸”做一道初中几何题——先拿到图标在屏幕上的坐标,再手动算出窗口应该出现的位置:

if let button = statusItem?.button, let _ = button.window?.screen {
    // 1. 获取按钮在全局屏幕坐标系中的位置和尺寸
    let buttonFrameInWindow = button.convert(button.bounds, to: nil)
    let buttonFrameInScreen = button.window!.convertToScreen(buttonFrameInWindow)

    let windowWidth = window.frame.width
    let windowHeight = window.frame.height

    // 2. 水平居中:让窗口中心点与按钮中心点对齐
    let xPos = buttonFrameInScreen.midX - (windowWidth / 2)

    // 3. 垂直定位:紧贴菜单栏底部,再往下偏移 5 个像素留点呼吸感
    let yPos = buttonFrameInScreen.minY - windowHeight - 5

    // 4. 应用计算好的新位置
    window.setFrame(NSRect(x: xPos, y: yPos, width: windowWidth, height: windowHeight), display: true)
}

这段代码的核心就是 midXminY 的计算。不管你用的是刘海屏 MacBook 还是外接显示器,也不管你把图标拖到了菜单栏哪个角落,窗口都会精准地出现在图标正下方。

省电秘诀:看不见的时候,别瞎忙

系统监控类工具最容易被人忽视的问题,就是监控本身也会耗电。如果你在后台不间断地高频读取 sysctl 或计算 CPU 时钟周期,用不了多久 MacBook 的电池就会被“监控”没电。

SysMonitor 的做法非常聪明:

  • 当毛玻璃面板打开时:每 2 秒刷新一次,保证界面流畅跟手。
  • 当你点别处或切换到别的应用时:触发 windowDidResignKey,面板自动淡出隐藏,同时把轮询间隔放宽到 5 秒。
extension AppDelegate: NSWindowDelegate {
    // 当窗口失去焦点(用户点击了屏幕其他区域)时自动隐藏
    func windowDidResignKey(_ notification: Notification) {
        if let window = widgetWindow, window.isVisible {
            hideWidgetWindow() // 执行淡出动画,并将轮询频率降至 5 秒一次
        }
    }
}

这种“按需呼吸”的策略,让这个小工具在后台几乎无感,真正做到“我监控着你,但我不用你操心”。

如何尝鲜

如果你也想试试这款原生监控工具,可以直接克隆源码并用 Xcode 构建。你的 Mac 需要运行 macOS 13 或更高版本。

# 克隆项目到本地
git clone https://github.com/fanioz/sysmonitor.git
cd sysmonitor
# 使用 Release 配置编译
xcodebuild -scheme sysmonitor -configuration Release build
# 运行生成的应用
open build/Release/sysmonitor.app

安装后,它会在菜单栏静静驻留,用最低调的方式告诉你 CPU、内存、磁盘和网络的一举一动;当你想深入了解时,点一下,那块漂亮的毛玻璃面板就会从图标下方顺滑展开。

一句话总结:SysMonitor 证明了原生体验不需要妥协——你可以同时拥有极简的菜单栏和精致的详情视图,还能让电池松一口气。如果你也厌倦了监控工具要么太简陋、要么太笨重,这个开源项目值得你点开源码好好研究。

直达网址:https://github.com/fanioz/sysmonitor

类似文章