iT邦幫忙

2024 iThome 鐵人賽

DAY 7
0

前幾天我們都在研究 UI 的顯示和樣式,但在 App 中,經常需要將資料載入 UI 並顯示給使用者看。今天,我們來認識 SwiftUI 的 State 與 Binding。這兩個工具在 SwiftUI 中非常重要,它們讓我們的介面能夠隨著資料變化自動更新,真的是既神奇又便利的功能。讓我們一起來看看 State 和 Binding 是如何運作的吧!

什麼是 State?

在 SwiftUI 中,State 是一種屬性包裝器(Property Wrapper),用來儲存和管理資料。使用時需要在前面加上 @,像這樣 @State。當我們用 @State 來宣告一個變數時,SwiftUI 會自動將這個變數存在 App 的某個地方,並且對應這個變數的 View 會自動監聽這個變數的變化。因此,當資料改變時,SwiftUI 會自動重新渲染相關的 View,我們就不需要手動去更新畫面了。

舉個例子,當我們在逛購物 App 時,想要買 6 瓶飲料,每次點擊增加數量的按鈕時,顯示數量的文字內容就會改變。這時候,我們就需要用 @State 來儲存這個文字內容,當按鈕被點擊時,State 的值會改變,SwiftUI 也會自動更新顯示的內容。

我們可以這樣試試看:

struct ContentView: View {
    @State private var buttonText: String = "Hello, SwiftUI!"

    var body: some View {
        VStack {
            Text(buttonText)
            Button("Tap me") {
                buttonText = "You tapped the button!"
            }
        }
    }
}

https://ooorito.com/wp-content/uploads/2024/08/State.gif

在這段程式碼中,我們用了 @State 來儲存 buttonText,當按鈕被點擊時,buttonText 的值改變了,文字的顯示一起更新。

參考資料:State | Apple Developer Documentation

什麼是 Binding?

有了 State 後,接下來就是 Binding。Binding 可以說是連接兩個元件之間資料的橋樑,它讓我們可以在不同的元件之間共享和同步資料。

當我們需要在一個元件中修改另一個元件的資料時,比如使用 ToggleTextFieldSlider 等元件,就可以使用 Binding 來達成這個目的。Binding 將 View 和 Model(資料)綁定在一起,實現雙向溝通的便利功能:

  • 當資料內容改變時,它會同步更新元件。
  • 操作元件時,資料也會同步修改。

讓我們來試試看這個範例:

struct ContentView: View {
    @State private var isOn: Bool = false

    var body: some View {
        VStack {
            Toggle(isOn: $isOn) {
                Text("Switch")
            }
            Text(isOn ? "The switch is ON" : "The switch is OFF")
        }
    }
}

我們希望讓 Toggle 與 State 變數 isOn 綁定,這樣就能在畫面上同步顯示開關的狀態。

SwiftUI 透過 Binding<Value> 型別來進行資料的綁定機制,其中 Value 代表資料的型別。由於 Toggle 的狀態只有開啟和關閉兩種,因此它綁定的資料型別是 Bool。所以 Toggle 元件中的參數 isOn 的型別為 Binding<Bool>

現在,我們只需要將 isOn 的 binding 傳入 Toggle 的 isOn 參數即可完成綁定。Swift 提供了一個方便的語法,只要在 @State 屬性前加上 $,就可以取得該屬性的 binding。如果忘記加上 $,程式會出現紅色錯誤,因為它並不是 Binding 型別。

https://ooorito.com/wp-content/uploads/2024/08/Binding.gif

在這個例子,Toggle 元件使用了 Binding 來連接 isOn 這個 State,當開關被切換時,isOn 的值會自動更新,並且讓 Text 顯示對應的內容。

使用 @Binding 在 SwiftUI 中共享資料

除了剛剛在父視窗中將 @State 屬性前加上 $ 來使用 Binding 以外,我們還可以在子視窗中直接使用 @Binding 來實現不同視窗之間的資料共享。當我們在父視窗中使用 @State 來管理資料時,可以將這些資料傳遞給子視窗,並在子視窗中使用 @Binding 來接收並操作這些資料。

父視窗使用 @State

在父視窗中,我們需要定義一個 @State 變數來管理資料。不過這部分我們剛剛已經寫好了,現在只需要將下方 Toggle 的部分改為我們的子視窗 ChildView:

struct ParentView: View {
    @State private var isOn: Bool = false

    var body: some View {
        VStack {
            Text("Switch is \(isOn ? "ON" : "OFF")")
            ChildView(isOn: $isOn) // 將 @State 變數透過 @Binding 傳遞給子視窗
        }
    }
}

在這裡,ParentView 使用 @State 來管理 isOn 變數,並將它作為 Binding 傳遞給子視窗 ChildView。

子視窗使用 @Binding

接著,我們在子視窗中接收這個 @Binding,並可以在子視窗中操作這些資料:

struct ChildView: View {
    @Binding var isOn: Bool

    var body: some View {
        Toggle("Toggle Switch", isOn: $isOn)
            .padding()
    }
}

在 ChildView 中,我們使用 @Binding 來接收父視窗傳遞的 isOn 變數。這樣,當使用者在 ChildView 中操作 Toggle 開關時,isOn 的狀態會自動更新,並同步反應到父視窗的顯示內容中。

https://ooorito.com/wp-content/uploads/2024/08/Binding.gif

參考資料:

總結

以往我們在使用 UIKit 時,如果想要採用 MVVM 架構,總是需要自行實作 Observer 來綁定 ViewModel 和 UI。然而,在 SwiftUI 中,State 和 Binding 可以自動幫助我們完成值與 View 的綁定來完成 View 的更新。透過理解並善用這些工具,我們可以更輕鬆地建立動態、互動的 UI。雖然一開始這些概念可能會有點抽象,也容易混淆,但隨著我們的練習,這些概念會變得越來越自然。


上一篇
Day 6: 挖掘 SwiftUI 的進階 View Modifiers
下一篇
Day 8: SwiftUI 中的 MVVM 架構初次使用
系列文
用 SwiftUI 掌控家庭日用品庫存12
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言