跳到內容

掌握 macOS 選單列圖示的動態狀態

寫 macOS App 時,最煩惱的就是選單列(Menu Bar)的圖示。你想讓使用者知道 App 正在運作,但又不希望動畫太過干擾。如果圖示只是靜態的,使用者很難判斷語音指令有沒有被接收,或是背景的 Agent 到底有沒有在做事。

要在精簡的選單列空間內,精準傳達 App 的當前狀態,你需要一套完整的圖示切換邏輯。這篇文章會帶你快速掌握如何控制圖示的各種狀態。

  • macOS App 專案原始碼 (apps/macos)
  • AppState 與 AppStateStore 存取權限

要在 5 分鐘內搞定圖示狀態切換,你需要了解以下四種主要狀態:

圖示預設會處於 Idle 狀態,有隨機的眨眼(blink)與微動(wiggle)。如果你需要暫停所有動作,可以將狀態設為 Paused,這時圖示會套用 appearsDisabled 效果並停止所有位移。

當語音喚醒偵測器聽到喚醒詞時,圖示會放大並顯示耳洞,確保使用者知道 App 正在聆聽。

// 當聽到喚醒詞時觸發
AppState.triggerVoiceEars(ttl: nil)
// 靜音 1 秒後停止
stopVoiceEars()

這會將圖示比例從 1.0 放大至 1.9 倍,並開啟 earHoles 渲染設定。

當 Agent 正在執行任務(如 WebChat 運行中)時,你可以觸發「小碎步」(scurry)微動效。

// 開始任務
AppStateStore.shared.setWorking(true)
// 結束任務
AppStateStore.shared.setWorking(false)

所有的圖示邏輯都由 CritterIconRenderer.makeIcon 處理。

  • 原始尺寸:18×18 pt 的 Template Image。
  • 輸出規格:渲染為 36×36 px 的 Retina 影像。
  • 碎步效果:在現有的 Idle 微動上,額外增加最高 1.0 的腿部晃動與水平抖動。

如果你的圖示一直維持在「工作狀態」沒有恢復,請檢查是否在非同步任務中漏掉重設指令。建議在執行任務時使用 defer 區塊,確保狀態一定會被重設:

AppStateStore.shared.setWorking(true)
defer {
AppStateStore.shared.setWorking(false)
}
// 執行你的長任務

為了避免圖示狀態因為任務掛掉而卡住,請確保 TTL(Time To Live)設定短於 10 秒。目前系統不建議透過外部 CLI 觸發耳朵或工作狀態,應保持由 App 內部訊號驅動,以避免狀態閃爍。

想要了解更多細節,或是需要自動化設定你的開發環境?請諮詢 AI Setup Assistant。

OpenClaw

OpenClaw Expert

還是卡住了?

如果這篇文件沒有解決你的情境,直接問 OpenClaw Expert,拿到可執行步驟。