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 中文版
iOS 18 新API:使用 Navigation Transition 創建 Hero 動畫式過場
SwiftUI 框架

iOS 18 新API:使用 Navigation Transition 創建 Hero 動畫式過場

Apple 的工程師可能早已認識到,許多 iOS 開發者都希望能夠重現 App Store 應用程式中的優雅 Hero 動畫。由於從頭實現這種動畫通常需要耗費大量時間與精力,Apple 在 iOS 18 SDK 中納入了這項功能。 透過這次更新,你現在只需少量的程式碼就能在自己的應用程式中實現類似的動畫過渡效果。這項重大改進讓開發者能夠創造出更具視覺吸引力且流暢的過渡效果,
如何使用 Vision APIs 從圖像中辨識文字
AI

如何使用 Vision APIs 從圖像中辨識文字

Vision 框架長期以來一直包含文字識別功能。我們已經有詳細的教程,向你展示如何使用 Vision 框架掃描圖像並執行文字識別。之前,我們使用了 VNImageRequestHandler 和 VNRecognizeTextRequest 來從圖像中提取文字。 多年來,Vision 框架已經顯著演變。在 iOS 18 中,Vision
iOS 18更新:SwiftUI 新功能介紹
SwiftUI 框架

iOS 18更新:SwiftUI 新功能介紹

SwiftUI的技術不斷演進,每次更新都讓 iOS 應用程式開發變得更加便捷。隨著 iOS 18 Beta 的推出,SwiftUI 引入了多個令人興奮的新功能,使開發者僅需幾行程式碼即可實現出色的效果。 本教學文章旨在探索這個版本中的幾項主要改進,幫助你了解如何運用這些新功能。 浮動標籤列 (Floating Tab Bar)SwiftUI中的標籤視圖(Tab
很好! 你已成功註冊。
歡迎回來! 你已成功登入。
你已成功訂閱 AppCoda 中文版 電子報。
你的連結已失效。
成功! 請檢查你的電子郵件以獲取用於登入的連結。
好! 你的付費資料已更新。
你的付費方式並未更新。