SwiftUI

2024 年 6 月 16 日

SwiftUI 在 macOS App 控制中心模組使用自訂圖片

已複製到剪貼板


在 SwiftUI 使用 MenuBarExtra 實作 macOS 上的控制中心模組時,使用系統圖片(SF Symbols)作 Icon 是最簡單的,不過我們也可以用自訂的圖片。

macOS 螢幕右上方的控制中心模組
macOS 螢幕右上方的控制中心模組

SwiftUI 的 MenuBarExtra 概覽

MenuBarExtra 是 Mac 螢幕右上方選單列中的功能,它可以是一個圖像或文字,可以用來提供一些 App 的常用功能,即使我們的 macOS app 不在活躍的狀態。

備註

我們在另外一篇文章詳細說明了如何用 SwiftUI 的 MenuBarExtra 實作 macOS 上的控制中心模組,以及使用文字與系統圖片(SF Symbols)來呈現模組 Icon。想了解更多,可以點擊這裡

此篇文章主要會分享如何使用自己的圖片來作為 MenuBarExtra 的縮圖 Icon,並且調整圖片大小。

SwiftUI 使用系統圖片作為 MenuBarExtra 的 Icon

用 SF Symbols 作為 MenuBarExtra 的縮圖 Icon 最簡單的方式,就是使用專門吃系統圖片的 MenuBarExtra init。

@main
struct XcodeProjectApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        MenuBarExtra( // macOS App 的控制中心模組
            "text for the accessibility system",
            systemImage: "swift"
        ) {
            StatusMenu()
        }
    }
}
使用系統圖片作為 SwiftUI MenuBarExtra 的 Icon
使用系統圖片作為 SwiftUI MenuBarExtra 的 Icon

如果不使用專門吃系統圖片的 MenuBarExtra init,也可以用更通用的 init,像這樣:

@main
struct XcodeProjectApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        MenuBarExtra { // macOS App 的控制中心模組
            StatusMenu()
        } label: {
            Image(systemName: "swift")
        }
    }
}

SwiftUI 使用自訂圖片作為 MenuBarExtra 的 Icon

如果我們想用自己的圖片或甚至是 AppIcon 作為 MenuBarExtra 的縮圖,就要使用上例通用的 init:

@main
struct XcodeProjectApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        MenuBarExtra { // macOS App 的控制中心模組
            StatusMenu()
        } label: {
            Image("XcodeProject")
                .resizable()
                .scaledToFit()
                .frame(width: 16, height: 16)
        }
    }
}

因為我們自己加到 App 專案裡的圖片通常都比較大張,而顯示在狀態列的 Icon 圖片都是小小的,所以我們可能會像上例這樣,再多設定圖片的大小。

但執行我們的專案後會發現,圖片並沒有如預期的變小,還是太大而且很醜很糊。

使用自訂圖片作為 SwiftUI MenuBarExtra 的 Icon 時,通常都會遇到破圖
使用自訂圖片作為 SwiftUI MenuBarExtra 的 Icon 時,通常都會遇到破圖

而如果專案裡的這張圖片又更大張的話,會完全顯示不出來。

SwiftUI MenuBarExtra 中的 label 無法再調整圖片大小

從上面的寫法與呈現結果來看,可以發現傳入 MenuBarExtra 的 label 是無法再調整大小的,所以我們必須在傳入前,就把合適得圖片準備好,再傳給 MenuBarExtra。

一個作法是,在 Assets.xcassets 中加入一個調整好比較小的圖片,專門給 MenuBarExtra 用,但這通常不會是我們想要的。而另一個就是用程式來把原圖片調小,寫法會像這樣:

@main
struct XcodeProjectApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        
        MenuBarExtra { // macOS App 的控制中心模組
            StatusMenu()
        } label: {
            let nsImage: NSImage = {
                let ratio = $0.size.width / $0.size.height
                $0.size.height = 16
                $0.size.width = 16 * ratio
                return $0
            }(NSImage(named: "XcodeProject") ?? NSImage())
            Image(nsImage: nsImage)
        }
    }
}

因為我們在 macOS 上,所以會使用 AppKit 中的 NSImage,這裡會先取原圖的長寬比(ratio),再將圖片的高設成我們想要的大小(16),然後寬就依照原比例縮放。如此,我們就將原本比較大張的圖先縮小了,而且也不失畫質,接下來就直接給 SwiftUI 的 Image 就行了。

SwiftUI MenuBarExtra with Right Custom Image
以自訂圖片作為 SwiftUI MenuBarExtra 的 Icon 時,順利調整 Icon 的大小

備註

我們有另外一篇文章詳細說明了如何在 macOS App 中取得 App Icon,並顯示出來。想了解更多,可以點擊這裡

分享文章

已複製到剪貼板

主題文章

查看 SwiftUI

超級感謝

關於 XcodeProject

XcodeProject 創立於 2023,致力於協助開發者探索 Apple 的創新世界,學習在 iOS、iPadOS、macOS、tvOS、visionOS 與 watchOS 上開發 App,發現眾多技術與框架,讓開發者獲得更多能力。


Contacts

Ricky Chuang

XcodeProject

RickyChuang.xcodeproj@gmail.com

XcodeProject 聯絡

contact.xcodeproj@gmail.com

最新文章