前幾天我們都在研究 UI 的顯示和樣式,但在 App 中,經常需要將資料載入 UI 並顯示給使用者看。今天,我們來認識 SwiftUI 的 State 與 Binding。這兩個工具在 SwiftUI 中非常重要,它們讓我們的介面能夠隨著資料變化自動更新,真的是既神奇又便利的功能。讓我們一起來看看 State 和 Binding 是如何運作的吧!
在 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!"
}
}
}
}
在這段程式碼中,我們用了 @State
來儲存 buttonText,當按鈕被點擊時,buttonText 的值改變了,文字的顯示一起更新。
有了 State 後,接下來就是 Binding。Binding 可以說是連接兩個元件之間資料的橋樑,它讓我們可以在不同的元件之間共享和同步資料。
當我們需要在一個元件中修改另一個元件的資料時,比如使用 Toggle
、TextField
、Slider
等元件,就可以使用 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 型別。
在這個例子,Toggle
元件使用了 Binding 來連接 isOn 這個 State,當開關被切換時,isOn 的值會自動更新,並且讓 Text
顯示對應的內容。
除了剛剛在父視窗中將 @State
屬性前加上 $ 來使用 Binding 以外,我們還可以在子視窗中直接使用 @Binding 來實現不同視窗之間的資料共享。當我們在父視窗中使用 @State
來管理資料時,可以將這些資料傳遞給子視窗,並在子視窗中使用 @Binding
來接收並操作這些資料。
在父視窗中,我們需要定義一個 @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
,並可以在子視窗中操作這些資料:
struct ChildView: View {
@Binding var isOn: Bool
var body: some View {
Toggle("Toggle Switch", isOn: $isOn)
.padding()
}
}
在 ChildView 中,我們使用 @Binding
來接收父視窗傳遞的 isOn 變數。這樣,當使用者在 ChildView 中操作 Toggle
開關時,isOn 的狀態會自動更新,並同步反應到父視窗的顯示內容中。
參考資料:
以往我們在使用 UIKit 時,如果想要採用 MVVM 架構,總是需要自行實作 Observer 來綁定 ViewModel 和 UI。然而,在 SwiftUI 中,State 和 Binding 可以自動幫助我們完成值與 View 的綁定來完成 View 的更新。透過理解並善用這些工具,我們可以更輕鬆地建立動態、互動的 UI。雖然一開始這些概念可能會有點抽象,也容易混淆,但隨著我們的練習,這些概念會變得越來越自然。