SwiftUI 框架

在 SwiftUI 利用 ToggleStyle 簡單建立客製化的切換按鈕

Toggle 是 SwiftUI 中很常用的視圖,讓使用者在開或關兩種狀態之間切換。這個控件可以為使用者提供簡單而直觀的界面,因此很多開發者都會用到它。在這篇文章中,我會帶大家在 SwiftUI 使用 ToggleStyle 協定,輕鬆地創建適合自己 App 設計和風格的 Toggle。
在 SwiftUI 利用 ToggleStyle 簡單建立客製化的切換按鈕
Photo by Isaac Li Shung Tan on Unsplash
In: SwiftUI 框架

Toggle 是 SwiftUI 中很常用的視圖,讓使用者在開或關兩種狀態之間切換。這個控件 (control) 可以為使用者提供簡單而直觀的界面,因此很多開發者都會用到它。舉個例子,我們可以在 App 中使用 Toggle,來控制開啟或關閉某些功能,或切換不同模式或選項。要在 SwiftUI App 中實作 Toggle 十分簡單,我們可以使用 ToggleStyle 協定,來創建適合我們 App 設計和風格的 Toggle。

在這篇教學文章中,我會帶大家了解這個 Toggle 視圖,並一起利用 ToggleStyle 構建幾個客製化 Toggle。

Toggle 的基礎使用

SwiftUI Sample Toggles

在 SwiftUI 中,我們有幾個方法可以使用 Toggle 視圖。最基本的使用方法是這樣的:

struct ContentView: View {
    @State private var isEnabled = false

    var body: some View {
        Toggle("Airplane Mode", isOn: $isEnabled)
    }
}

在這裡,我們使用 text description 和 binding 來初始化 Toggle 視圖,而 Toggle 的狀態是由狀態變數 (state variable) 所控制的。這段程式碼會建構出上圖那個帶有 text label 的基本 toggle。

如果我們想客製化文本的樣式,Toggle 還有另一個初始化器 (initializer)。我們可以在閉包中這樣設定 Text 視圖的外觀:

Toggle(isOn: $isEnabled) {
    Text("Airplane mode")
        .font(.system(.title, design: .rounded))
        .bold()
}

我們還可以這樣客製化 description,來添加一個圖像:

Toggle(isOn: $isEnabled) {
    HStack {
        Text("Airplane mode")
        Image(systemName: "airplane")

    }
    .font(.system(size: 20))
}

最後我們會看到一個更漂亮的 switch。

swiftui-switch-with-image

改變 Toggle 的樣式

在預設設定下,Toggle 視圖是使用 switch 樣式的。我們可以使用 .toggleStyle 修飾符,來把樣式從 switch 轉換成 button

.toggleStyle(.button)

比如說,如果我們想建立一個書籤按鈕,就可以使用以下的程式碼:

struct ContentView: View {
    @State private var isBookmarked = false

    var body: some View {
        Toggle(isOn: $isBookmarked) {
            Image(systemName: isBookmarked ? "bookmark.fill" : "bookmark")
                .font(.system(size: 50))
        }
        .tint(.green)
        .toggleStyle(.button)
        .clipShape(Circle())
    }
}

整個操作十分相似,只是這次我們會用 .toggleStyle 修飾符,來告訴 Toggle 使用 .button 樣式。如此一來,SwiftUI 就不會把 toggle 顯示為一個開關,而是會顯示為一個按鈕,而按鈕會根據狀態改變其外觀。

swiftui-toggle-button-style

使用 ToggleStyle 來建立一個客製化 Toggle

在大部分情況下,預設的 toggle 樣式都足夠應付我們的需要。不過,在某些情況下,我們可能想要創建客製化的樣式,來切合 App 的風格。接下來,讓我們看看如何創建自己的客製化 toggle 吧!簡單來說,我們可以採用 ToggleStyle 協定,並實作所需的 makeBody(configuration:) 函數,來創建自己的樣式:

struct CustomToggleStyle: ToggleStyle {
    func makeBody(configuration: Configuration) -> some View {
        // Your implementation
    }
}

讓我們從簡單的開始!首先,我們會構建一個 toggle switch,並客製化其背景顏色和符號。

swiftui-togglestyle-example

要構建這個 toggle switch,讓我們建立一個新的結構 SymbolToggleStyle,它符合 ToggleStyle 協定:

struct SymbolToggleStyle: ToggleStyle {

    var systemImage: String = "checkmark"
    var activeColor: Color = .green

    func makeBody(configuration: Configuration) -> some View {
        HStack {
            configuration.label

            Spacer()

            RoundedRectangle(cornerRadius: 30)
                .fill(configuration.isOn ? activeColor : Color(.systemGray5))
                .overlay {
                    Circle()
                        .fill(.white)
                        .padding(3)
                        .overlay {
                            Image(systemName: systemImage)
                                .foregroundColor(configuration.isOn ? activeColor : Color(.systemGray5))
                        }
                        .offset(x: configuration.isOn ? 10 : -10)

                }
                .frame(width: 50, height: 32)
                .onTapGesture {
                    withAnimation(.spring()) {
                        configuration.isOn.toggle()
                    }
                }
        }
    }
}

這個結構有兩個參數,一個是符號的圖像名稱,另一個是 switch 的顏色。我們會在 makeBody 函數中從頭開始構建 toggle,包括將 text label 放在一側,switch 放在另一側。

configuration 參數為我們提供了兩個信息:toggle 的 text label(即 configuration.label)和狀態(即 configuration.isOn)。在上面的程式碼中,我們使用 HStack 排列 text label 和圓角矩形。另外,我們在圓角矩形上添加一個圓形來構建 switch,並在圓形上面疊加一個圖像視圖來顯示符號。在預設情況下,圖像設置為顯示一個 checkmark。

如我剛剛所說,我們會從頭開始創建一個 switch,因此我們需要處理點擊手勢 (tap gesture),並切換 switch 的狀態。此外,當狀態改變時,我們會改變 offset value 來移動圓形。

我們可以這樣套用 toggleStyle 修飾符,來使用這個客製化 toggle 樣式:

Toggle(isOn: $isEnabled) {
    Text("Airplane mode")
}
.toggleStyle(SymbolToggleStyle(systemImage: "airplane", activeColor: .purple))

以上的程式碼會利用 SymbolToggleStyle 來創建一個 toggle。

建立一個動畫化的圖像 Toggle

swiftui-toggle-light-dark

接下來,讓我們構建另一個 toggle 樣式,它在開啟和關閉的狀態下會顯示不同的圖像。在這個專案中,我們會使用以下這兩個圖像:

下載以上兩張圖像後,把它們匯入到 SwiftUI 專案的 asset catalog 中。然後,我們這樣建立新的 toggle 樣式:

struct ImageToggleStyle: ToggleStyle {

    var onImage = "dark"
    var offImage = "light"

    func makeBody(configuration: Configuration) -> some View {

        HStack {
            configuration.label

            Spacer()

            RoundedRectangle(cornerRadius: 30)
                .fill(configuration.isOn ? .black : Color(.systemGray5))
                .overlay {
                    Image(configuration.isOn ? onImage : offImage)
                        .resizable()
                        .scaledToFill()
                        .clipShape(Circle())
                        .padding(5)
                        .rotationEffect(.degrees(configuration.isOn ? 0 : -360))
                        .offset(x: configuration.isOn ? 10 : -10)
                }
                .frame(width: 50, height: 32)
                .onTapGesture {
                    withAnimation(.spring()) {
                        configuration.isOn.toggle()
                    }
                }
        }
    }
}

ImageToggleStyle 結構有開啟和關閉圖像的兩個參數。實作 switch 的步驟和前文非常相似,只是我們這次不會使用 Circle 視圖來創建 switch,而是使用圖像視圖來顯示開啟和關閉的圖像。

我們也添加了 rotationEffect 修飾符,為 switch 的狀態轉換設置動畫。

同樣地,如果要使用這個 toggle 樣式,我們只需要把 .toggleStyle 修飾符附加到 toggle 視圖即可:

VStack {
    Toggle(isOn: $isEnabled) {
        Text("Light/Dark mode")
            .foregroundColor(isEnabled ? .white : .black)
    }
    .toggleStyle(ImageToggleStyle())
    .padding()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(isEnabled ? .black.opacity(0.6) : .white)

簡單存取 Toggle 樣式

為了簡化存取客製化 toggle 樣式的步驟,我們可以在 ToggleStyle 的 extension 添加一個狀態變數:

extension ToggleStyle where Self == ImageToggleStyle {

    static var image: ImageToggleStyle { .init() }
}

在這個情況下,我們可以使用 dot syntax 應用 toggle 樣式:

Toggle(isOn: $isEnabled) {
    Text("Light/Dark mode")
        .foregroundColor(isEnabled ? .white : .black)
}
.toggleStyle(.image)

總結

在這篇教學文章中,我們學會了如何在 SwiftUI 創建客製化 Toggle 的樣式。我們可以使用 ToggleStyle 協定,來製作出獨特而漂亮的 Toggle。如果大家想更深入了解 SwiftUI 和 ToggleStyle 協定,可以參閱我們的《精通SwiftUI》一書,當中會有更多技巧和完整的源程式碼。

譯者簡介:Kelly Chan-AppCoda 編輯小姐。
作者
Simon Ng
軟體工程師,AppCoda 創辦人。著有《iOS 17 App 程式設計實戰心法》、《iOS 17 App程式設計進階攻略》以及《精通SwiftUI》。曾任職於HSBC, FedEx等跨國企業,專責軟體開發、系統設計。2012年創立AppCoda技術部落格,定期發表iOS程式教學文章。現時專注發展AppCoda業務,致力於iOS程式教學、產品設計及開發。你可以到推特與我聯絡。
評論
更多來自 AppCoda 中文版
如何使用 Swift 整合 Google Gemini AI
SwiftUI 框架

如何使用 Swift 整合 Google Gemini AI

在即將到來的 WWDC,Apple 預計將會發佈一個本地端的大型語言模型 (LLM)。 接下來的 iOS SDK 版本將讓開發者更輕易地整合 AI 功能至他們的應用程式中。然而,當我們正在等待 Apple 推出自家的生成 AI 模型時,其他公司(如 OpenAI
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。