精通 SwiftUI - iOS 17 版

第 3 章
圖片與標籤的處理

現在你應該對於 SwiftUI 有了基本概念,並了解如何顯示文字內容,本章我們來看如何顯示圖片。我們也會學習標籤(Label)的用法。

除了文字之外,圖片是 iOS App 開發的另外一個基本元件。SwiftUI 提供一個名為 Image 的視圖,來讓開發者將圖片渲染在螢幕上。首前一章的內容相似,我會建立一個簡單的 App,以示範如何進行圖片的處理。本章可歸納為以下幾個主題:

  • 什麼是SF Symbol,以及如何顯示一個系統圖片?
  • 如何顯示我們自己的圖片?
  • 如何調整圖片大小?
  • 如何使用 ignoresSafeArea 來顯示一個全螢幕的圖片?
  • 如何建立一個圓形圖片?
  • 如何在圖片上應用重疊?

使用 SwiftUI 來建立新專案

首先,開啟Xcode 並使用「App」模板( 在 iOS 分類下),來建立一個新專案。輸入專案的名稱,並設定為「SwiftUIImage」。關於組織名稱,你可以設定為你自己公司或組織名稱, 同樣的,我使用「com.appcoda」,但你可以使用自己的值。要使用SwiftUI 的話,請確認在「User Interface」選項中選取 「SwiftUI」然後點擊「Next」,選取要建立專案的資料夾, 如圖 3.1 所示。

圖 3.1. 建立一個新專案
圖 3.1. 建立一個新專案

專案儲存完成之後,Xcode 即會載入 ContentView.swift 檔,並顯示一個「設計/ 預覽」畫布,如圖 3.2 所示。

圖 3.2. 預覽所產生的程式
圖 3.2. 預覽所產生的程式

SF Symbols 介紹

超過 4,000 個可設定的標誌,SF Symbols 無縫整合了 Apple 平台的 San Francisco 系統字型,每一個標誌皆設定了不同的權重與比例,可以自動對齊文字標籤,並支援動態型態(Dynamic type)與粗體字(Bold Text)輔助功能,你也可以輸出這些文字,以向量圖形編輯工具來進一步編輯,建立具有共享特點與可用性的自訂標誌。SF Symbols 4 加入 700 多個新符號、增強的顏色自定義、新的檢查器以及對自定義符號的改進支持。

在教你如何在螢幕顯示圖片之前,我們先談一下關於圖片的來源。當然,你可以在 App 中提供自己的圖片。從 iOS 13 開始,Apple 導入名為「SF Symbols」的大量系統圖片,可以讓開發者在任何 App 中使用。iOS 16 進一步修改版釋出了 SF Symbol 4 ,新增了 700 個標誌,並增強的顏色設置。

這些圖片是作為標誌用,由於它整合了內建的 San Francisco 字型,因此使用這些標誌, 並不需要額外的安裝,只要你的 App 是部署在執行 iOS 13(或之後的版本)的裝置,你就可以直接取得這些標誌。但你要注意,現在有五組不同的符號需要考慮:

  • SF Symbols v1.1 適用於 iOS/iPadOS/tvOS/Mac Catalyst 13.0, watchOS 6.0 和 macOS 11.0
  • SF Symbols v2.0 適用於 iOS/iPadOS/tvOS/Mac Catalyst 14.0, watchOS 7.0 和 macOS 11.0
  • SF Symbols v2.1 適用於 iOS/iPadOS/tvOS/Mac Catalyst 14.2, watchOS 7.1 和 macOS 11.0
  • SF Symbols v2.2 適用於 iOS/iPadOS/tvOS/Mac Catalyst 14.5, watchOS 7.4 和 macOS 11.3
  • SF Symbols v3.0 適用於 iOS/iPadOS/tvOS/Mac Catalyst 15.0, watchOS 8.0 和 macOS 12.0
  • SF Symbols v4.0 適用於 iOS/iPadOS/tvOS/Mac Catalyst 16.0, watchOS 9.0 和 macOS 13.0
  • SF Symbols v5.0 適用於 iOS/iPadOS/tvOS/Mac Catalyst 17.0, watchOS 10.0 和 macOS 14.0

當要使用這些標誌時,你需要準備的是找到標誌名稱。由於有超過 5,000 個符號可供使用,Apple 釋出一個名為 SF Symbols (https://developer.apple.com/sf-symbols/) 個標誌可以讓你使用,因此你可以很容易地找到你要的標誌來配合你的設計。我極力推薦你在進行下一節之前,先安裝這個 App。

圖 3.3 SF Symbols App
圖 3.3 SF Symbols App

顯示系統圖片

想要在螢幕上顯示系統圖片的話,你可以初始化一個 Image 視圖,加上 systemName 參數,如下所示:

Image(systemName: "cloud.heavyrain")

這將會建立一個圖片視圖,並載入指定的系統圖片。如前所述,SF Symbols 與 San Francisco 字型無縫整合。你可以很容易地應用 font 修飾器來進行圖片的縮放。

Image(systemName: "cloud.heavyrain")
    .font(.system(size: 100))

你可以變更字型大小來觀察圖片的反應,如圖 3.4 所示。

圖 3.4. 顯示系統圖片
圖 3.4. 顯示系統圖片

同樣的,因為系統圖片實際上是一個字型,你可以應用其他的修飾器如之前所學過的 foregroundColor,來變更它的外觀。

例如:要變更顏色為藍色,你可以撰寫程式如下:

Image(systemName: "cloud.heavyrain")
    .font(.system(size: 100))
    .foregroundStyle(.blue)

要加入一個下拉式陰影效果(drop shadow effect ),你只需要使用 shadow 修飾器:

Image(systemName: "cloud.heavyrain")
    .font(.system(size: 100))
    .foregroundStyle(.blue)
    .shadow(color: .gray, radius: 10, x: 0, y: 10)

使用自己的圖片

在前面,我們使用了Apple 內建的圖片。不過,你可能會在App 中使用自己的圖片。那麼,要如何使用 Image 視圖來載入圖片呢?

Note: 你可以任意使用自己的圖片,若是你沒有合適的圖片,也可以至 unsplash.com 下載圖片 (https://unsplash.com/photos/Q0-fOL2nqZc) ,以方便繼續後面的內容。圖片下載完成之後,請將檔名改成「paris.jpg」。

在你的專案能夠使用圖片之前,首先你必須先將圖片匯入素材目錄( Asset Catalog ), 也就是 Assets。假設你已經準備好圖片(paris.jpg ),按下 command+0 鍵來開啟專案導覽器(Project Navigator ),並選取 Assets。現在開啟 Finder,並將圖片拖曳至大綱視圖(Outline View ),如圖 3.5 所示。

圖 3.5 將圖片加至素材目錄
圖 3.5 將圖片加至素材目錄

如果你是 iOS App 開發新手,這個素材目錄是你儲存應用程式資源如圖片、顏色與資料的地方。當你將圖片放入素材目錄時,你可以參照它的名稱來下載圖片。另外,你可以設定要載入圖片的裝置(例如:只限 iPhone )。

要在螢幕上顯示圖片,可撰寫程式如下:

Image("paris")

你只需要指定圖片名稱,可在預覽畫布中見到圖片。然而,由於圖片是高解析度圖片( 4437×6656 像素),你只能見到部分圖片,如圖 3.6 所示。

圖 3.6. 載入自訂的圖片
圖 3.6. 載入自訂的圖片

調整圖片大小

那麼,如何調整圖片呢?你可以使用 resizable 修飾器,如下所示:

Image("paris")
    .resizable()

預設上,圖片大小調整是使用「延伸」(stretch )模式。這表示原始圖片將會被放大到填滿整個螢幕畫面(除了頂部與底部區域之外),如圖 3.7 所示。

圖 3.7. 以resizable 修飾器調整圖片大小
圖 3.7. 以resizable 修飾器調整圖片大小

技術上而言,這個圖片填滿了整個 iOS 所定義的安全區域(Safe Area )。安全區域的觀念已經存在一段頗長的時間了,定義為安全佈局UI 元件的視圖區域。舉例而言,如圖 3.7 所示,這個安全區域不包含頂部列(Top Bar )(也就是狀態列)與底部列(Bottom Bar ) 的區域。安全區域可以避免你不小心隱藏了系統 UI 元件,例如:狀態列(Status Bar )、導覽列(Navigation Bar )與標籤列(Tab Bar )。

既然我們正好說到這件事, 若是你想要顯示全螢幕圖片, 你可以設定 ignoringSafeArea 修飾器來忽略安全區域,如圖 3.8 所示。

圖 3.8 忽略安全區域
圖 3.8 忽略安全區域

你可以針對特定的邊緣來忽略安全區域,例如:要忽略底部邊緣的安全區域,你只要傳送 .bottom 作為參數即可:

.ignoresSafeArea(.container, edges: .bottom)

Aspect Fit 與 Aspect Fill

如果你看一下前一小節這兩張圖片,並與原來的做比對,你應該會發現長寬比(aspect ratio )有些失真。這個延伸模式不會去管圖片的長寬比,它只是將每一邊延伸來填滿安全區域而已。如圖 3.9 所示,要保持原來的長寬比的話,你可以像這樣應用 scaledToFit 修飾器:

Image("paris")
    .resizable()
    .scaledToFit()
 圖 3.9 縮放圖片保持原來的長寬比
圖 3.9 縮放圖片保持原來的長寬比

另外,你可以使用 aspectRatio 修飾器,並設定內容模式(Content Mode)為. fit,這會達成同樣的結果。

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fit)

在某些情況下,你想要圖片的長寬比保持一樣,但儘可能地延伸,則你可以應用 .fill 內容模式:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fill)

我們試著來限制圖片的大小,這有助於你對這兩種模式能更了解。frame 修飾器可以讓你控制視圖的大小。舉例而言,設定框架(frame )的寬度為「300 點」,圖片的寬度將會限制在 300 點,如圖 3.10 所示。

圖 3.10. 利用 frame 控制圖片的寬度
圖 3.10. 利用 frame 控制圖片的寬度

現在將 Image 程式以下面的程式碼取代:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 300)

這張圖片會被縮小,但是仍保持原始長寬比。如果你變更內容模式為 .fill,圖片看起來與圖 3.7 幾乎相同,然而當你使用selectable 模式並仔細看圖 3.11,長寬比是維持不變的。

圖 3.11. 使用.fill 內容模式
圖 3.11. 使用.fill 內容模式

你可能會注意到圖片的寬度不是我們想要的,它依然占滿整個螢幕寬度。要正確運作的話,你必須使用 clipped 修飾器來消除視圖額外的部分,如圖 3.12 所示。

圖 3.12. 使用.clipped 來裁切視圖
圖 3.12. 使用.clipped 來裁切視圖

建立圓形圖片

除了將圖片裁切為長方形之外,SwiftUI 提供其他修飾器來讓你將圖片裁成不同的形狀,例如:圓形。舉例而言,如果你想要建立圓形圖片,你可以像這樣使用 clipShape 修飾器:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 300)
    .clipShape(Circle())

另外,你可以使用 .circle 代替 Circle()

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 300)
    .clipShape(.circle)

這裡我們指定將圖片裁成圓形。你可以傳送不同參數(如 Ellipse() )來建立不同形狀的圖片,圖 3.13 為一些範例。

圖 3.13. 使用.clipShape 修飾器來建立不同形狀的圖片
圖 3.13. 使用.clipShape 修飾器來建立不同形狀的圖片

不透明度的調整

SwiftUI 內建了名為 opacity 的修飾器,你可以使用這個修飾器來控制圖片(或者任何視圖)的不透明度。你傳送一個介於0 與1 的值來指定圖片的不透明度。這裡,「0」代表視圖完全透明,「1」則代表完全不透明。

舉例而言,如果你對圖片視圖應用了opacity 修飾器,並設定其值為「0.5」,則這個圖片將會呈現半透明(partially transparent ),如圖 3.14 所示。

圖 3.14 調整不透明度為50 %
圖 3.14 調整不透明度為50 %

應用圖片重疊

在設計App 時,有時你需要將另一個圖片或文字分層放置在圖片視圖之上。SwiftUI 框架提供一個名為「overlay」的修飾器給開發者,來將圖片進行重疊(Overlay ),例如:你要重疊一個系統圖片(如 heart.fill )至目前的圖片,你可以撰寫程式如下:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fill)
    .frame(width: 300)
    .clipShape(.circle)
    .overlay(
        Image(systemName: "heart.fill")
            .font(.system(size: 50))
            .foregroundColor(.black)
            .opacity(0.5)
    )

程式中的 .overlay 修飾器帶入一個 View 作為參數。在上列的程式中,我們建立其他的圖片(如 heart.fill ),並將其重疊在目前圖片(如 Paris )之上,如圖 3.15 所示。

圖 3.15 在目前的圖片上應用重疊
圖 3.15 在目前的圖片上應用重疊

事實上,你可以採用任何視圖來做重疊。例如:你可以重疊一個 Text 視圖在圖片之上。程式寫法如下:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .overlay(

        Text("If you are lucky enough to have lived in Paris as a young man, then wherever you go for the rest of your life it stays with you, for Paris is a moveable feast.\n\n- Ernest Hemingway")
            .fontWeight(.heavy)
            .font(.system(.headline, design: .rounded))
            .foregroundStyle(.white)
            .padding()
            .background(Color.black)
            .cornerRadius(10)
            .opacity(0.8)
            .padding(),

        alignment: .top

    )

overlay 修飾器,你只需要建立一個 Text 視圖,而這個文字視圖將會作為圖片上的重疊物件。我相信你已經熟悉了 Text 視圖的修飾器,我們在前面的章節已經有介紹過。我們只是變更字型與顏色,除此之外,我們加入了間距與背景顏色。另外,要特別說明的是 alignment 參數,對於 overlay 修飾器,你可以提供一個可選值(Optional Value )來調整視圖的對齊。預設是置中對齊,這裡我們想要將文字重疊於圖片之上,如圖 3.16 所示。你可以自己將值變更為「.center」或者「.bottom」,來看看結果為何。

圖3.16 在目前的圖片上應用重疊
圖3.16 在目前的圖片上應用重疊

以重疊來使圖片變暗

你不止可以重疊圖片或文字在另一張圖片上,你也可以應用重疊來使圖片變暗。將 Image 程式以下列程式替代,並看一下效果:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .overlay(
        Rectangle()
            .foregroundStyle(.black)
            .opacity(0.4)
    )

我們在圖片上畫一個矩形(Rectangle ),並將其前景色設定為「black」。為了達到變暗(darken )效果,我們設定不透明度為「0.4」,也就是 40% 的不透明度,圖片現在應該變暗了。

也可以將程式重寫如下完成一樣的效果:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .overlay(
        Color.black
            .opacity(0.4)
    )

在 SwiftUI,正好 Color 也是一個視圖,因此我們可以使用 Color.black 作為上層來將下層的圖片變暗。

當你想要將一些亮色文字重疊在太亮的圖片上時,這個技術尤其有用。我們將 Image 程式替換如下:

Image("paris")
    .resizable()
    .aspectRatio(contentMode: .fit)
    .frame(width: 300)
    .overlay(
        Color.black
            .opacity(0.4)
            .overlay(
                Text("Paris")
                    .font(.largeTitle)
                    .fontWeight(.black)
                    .foregroundStyle(.white)
                    .frame(width: 200)
            )
    )

如前所述,這個 overlay 修飾器不限於 Image,你也可以將它應用在其他視圖上。在上列的程式中,我們使用「Color.black」來使圖片變暗。此外,我們也重疊並放置了一個 Text。如果你的步驟都正確的話,你應該會見到一個「Paris」的文字放置在深色的圖片上面,如圖 3.17 所示。

圖 3.17. 使圖片變暗並應用文字重疊
圖 3.17. 使圖片變暗並應用文字重疊

使用有顏色的 SF Symbols

自 iOS 15 推出後,SF Symbols 提供四種渲染模式,可以將顏色應用於符號。 根據所選擇的模式,你可以為符號填上單色或多種顏色。 例如,cloud.sun.rain 是一個支持Palette Rendering 的符號。 你可以對符號應用兩種或多種對比色。 下圖顯示如何使用 SF Symbols 應用程式測試調色板。

圖 3.18. 在 SF Symbols 中使用調色板
圖 3.18. 在 SF Symbols 中使用調色板

在 SwiftUI 中,你可以加入 symbolRenderingMode 修飾器來更改模式。 要建立具有多種顏色的相同符號,你可以編寫如下程式碼:

Image(systemName: "square.and.arrow.down")
    .symbolRenderingMode(.palette)
    .foregroundStyle(.indigo, .yellow, .gray)
    .font(.system(size: 200))

我們在程式碼中指定使用palette 模式,然後使用foregroundStyle 修飾器使用顏色。

可變顏色(Variable Colors)

自 iOS 16 開始,SF Symbols 添加了一個名為 Variable Color 的新功能。 你可以通過更改百分比值來調整符號的顏色。 這在使用某些符號表示進度時特別有用。

你可以下載 SF Symbols 4 (https://developer.apple.com/sf-symbols/) 以試用此新功能。 安裝應用程式後,選擇 Variable 類別並選擇其中一個符號。 在檢查器中,你可以選取 Variable Color 按鈕來啟用該功能。 當你更改百分比值時,符號會對更改做出反應並填充其中的一部分。 以 slowmo 符號為例。 當你將百分比值設置為 60% 時,僅填充一些條形以表示進度。

圖 3.19. 在 SF Symbols app 使用 Variable Colors
圖 3.19. 在 SF Symbols app 使用 Variable Colors

可變顏色適用於 SF Symbols 內的每種渲染模式(Rendering mode)。 你可以試試更改為其他渲染模式以查看效果。

至於,要在程式碼中設置百分比值,你可以在建立 Image 視圖時,加入 variableValue 參數並將其與百分比值一起傳遞:

Image(systemName: "slowmo", variableValue: 0.6)
    .symbolRenderingMode(.palette)
    .foregroundStyle(.indigo)
    .font(.largeTitle)

本章小結

在本章中,我介紹了如何以 SwiftUI 處理圖片。SwiftUI 已經讓開發者很容易顯示圖片, 並讓我們使用不同的修飾器來產生各種的圖片效果。如果你是獨立開發者,這些新導入的 SF Symbols 會節省你尋找第三方圖示的時間。

在本章所準備的範例檔中,有完整的專案可以下載: