IconCard 📦

以「SF Symbol 為前景,透明方紙為背景」的元件,適合用於當遮罩或反面遮罩。

如果遮罩圖與要剪的紙一樣大,用 SystemImage 📦 就可以。 如果遮罩圖較小、要剪的紙較大,用 IconCard 📦

下圖顯示 img (IconCard) 從套用 .foregroundColor(.black)、.background(Color.white)、.compositingGroup()、.luminanceToAlpha(),一直到 paper (紅色星點紙) 套用 .mask() 的整個過程。

這個過程後來被濃縮成一個 View extension:.inverseMask() 🌀

左上角是 IconCard 的原圖 (img)
import SwiftUI
import Workaround   // for `SystemImage`

/// # 📦 IconCard
/// - icon: SF Symbol 名稱。
/// - size: ⚠️ 注意:這是圖示大小,不是整張卡的大小‼️
/// ## Example
/// ````
/// IconCard(icon: "heart.fill", size: 32)
/// ````
public struct IconCard: View {
    
    // properties
    let iconSize: CGFloat   // icon size
    let icon    : String    // icon name
    
    /// public init
    public init(_ icon: String, size: CGFloat = 32) {
        self.icon     = icon
        self.iconSize = size
    }
    
    // body
    public var body: some View {
        
        // 1. 選用 ZStack,讓物件可以在上下層間輕鬆堆疊。
        // ⭐️ 先不限制 ZStack 的大小,它的大小由外部環境決定。
        ZStack {
            
            // 2. 先準備一張「透明紙」:這裡有兩個用意 ⭐️ 
            //    1. 用 Rectangle 來定義此「元件的大小」(否則會以下面的 SystemImage 為準)。
            //    2. 先指定 fg = .clear,將來如果整個元件再被設定 .foreground() 時,
            //       - Rectangle 的 fg 還是 .clear (不會被 overridden‼️)
            //       - SystemImage 的 fg 因為還沒被設定過,所以就可以被改寫。
            Rectangle()
                .foregroundColor(.clear)             // ⭐️ 指定「透明色」!
            
            // 3. 然後在上面畫圖示,並設定圖示大小。
            // ⭐️ 注意:雖然沒有指定前景色,但在深色模式下,會用「白色」表示。
            SystemImage(icon)
                .frame(width: iconSize, height: iconSize)
        } // container (ZStack)
        
    } // body
}

Last updated

Was this helpful?