SwiftUI 推出了兩個 Property Wrapper – @State and @Binding。利用它們可以達到變數的 Two-way Binding 功能。也就是當變數的值改變時,它會重新被顯示。本章藉由製作一個 Custom View 來展示如何使用 @State 和 @Binding。
@Binding
宣告一個 View 叫 CounterView
。它主要顯示 counter
變數的值,然後有兩個 Button 可以加減 counter
。
CounterView.counter
變數被宣告為 @Binding
。如果只是單純的 var counter: Int
,那 Parent View 傳值給 CounterView(counter:)
時,就只是單純的傳值。也就是說,不論 CounterView
怎麼設值給 CounterView.counter
,Parent View 的 counter
都不會改變。
但是,加上 @Binding
後,CounterView.counter
會連結 (connect) Parent View 的 counter
。所以當 CounterView
設值給 CounterView.counter
時 Parent View 的 counter
也會改變。
struct CounterView: View { @Binding var counter: Int var body: some View { HStack { Text(String(counter)) Button(action: { self.counter -= 1 }, label: { Text("-") }) Button(action: { self.counter += 1 }, label: { Text("+") }) } .padding() } } struct CounterView_Previews: PreviewProvider { static var previews: some View { CounterView(counter: .constant(0)) } }
@State
ContentView.counter
變數被宣告為 @State
。所以當 counter
的值被變時,ContentView
就會被設為無效 (invalidated),導致 ContentView
被重新計算並重畫。這也就是雙向綁定 (Two-way Binding) 的使用。
但是這僅僅只限於在 ContentView
裡面。如果我們將 counter
變數傳給 CounterView
,並希望當 CounterView
改變 counter
的值時,View 也可以被 Invalidated。那這就要靠 @Binding
的配合了。
因為 CounterView.counter
是宣告為 @Binding
,那 ContentView
要傳 counter
給 CounterView
時,就要加上 $ 前綴符號。
struct ContentView: View { @State var counter = 0 var body: some View { VStack { Text("Counter: \(counter)") CounterView(counter: $counter) } } }
結語
@State 和 @Binding 是 SwiftUI 中很重要的一個功能。它們讓 SwiftUI 實現 Two-way Binding。讓開發者在管理 Parent View 和 Child Views 之間的變數,變得相當地容易,也易於了解。對於網頁開發者,這是很平常的事情,但對於 App 開發者而言,這是全新的開發方式。