本文原創(chuàng)作者為: Martin Lasek
原文鏈接:https://medium.com/flawless-app-stories/swiftui-understanding-state-8afa23fd9f1f
在這個教程中,我們將會深入地去理解 State 的基本原理 -- State 是什么纤壁,為什么它起到很好的作用,還有就是如何使用它捺信。
索引
- 創(chuàng)建一個SwiftUI項目工程
- 新建一個
Text
和一個Button
的 view - 理解 State
開始前的準備
為了能夠使用SwiftUI酌媒,需要升級你的系統(tǒng)到macOS Catalina,還有安裝Xcode 11迄靠。
1. 創(chuàng)建一個新的SwiftUI項目
在Xcode中秒咨, 就跟之前創(chuàng)建iOS項目一樣新建一個項目,選擇 Single View App:
接下來梨水,在確認新建項目之前要確保 Use SwiftUI 是選中狀態(tài):
2. 新建一個Text
和一個Button
的 view
新建完項目之后拭荤,你將會看到3個 .swift
文件,但我們只要關注 ContentView.swift這個文件疫诽。在這個文件中舅世,我們會看到一個 Text
view,讓我們來添加一個 Button
view 在里面吧奇徒。
import SwiftUI
struct ContentView : View {
var body: some View {
VStack {
Text("Hello World")
Button(
action: { print("Hey Listen!") },
label: { Text("Switch") }
)
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
讓我們來分析這里面的每一行代碼吧〕牵現(xiàn)在 VStack 允許我們在垂直方向進行頁面布局。那和它一起配合使用的 HStack摩钙,你猜到了 -- 它允許我們進行水平方向布局罢低。
你已經能夠感受到 SwiftUI 有多么重點關注在 closures(閉包)和 Views 上了吧。
這個Button
view創(chuàng)建的時候用了兩個閉包胖笛。我們傳進去的第一個閉包將會在 Button 點擊的時候執(zhí)行网持。第二個閉包讓我們能夠 return 將會在 Button 里面顯示的一個 View。
如果你現(xiàn)在允許你的代碼的話长踊,你應該會看到這樣的效果:
讓我們來為 Text
定義一些風格功舀,讓它可以讓看起來更好一些:
import SwiftUI
struct ContentView : View {
var body: some View {
VStack {
Text("Hello World")
.frame(
width: UIScreen.main.bounds.width,
height: 50
)
.background(Color.blue)
.foregroundColor(Color.white)
.padding(10)
Button(
action: { print("Hey Listen!") },
label: { Text("Switch") }
)
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
如果你覺得這個有些嚇人的話,不用擔心的身弊。這只是我們的一個新功能而已辟汰。就像我們在那時候學會了像這樣去設置UIView的背景顏色:
myView.backgroundColor = .blue
以后我們閉著眼睛都能在SwiftUI中去實現(xiàn)backgroundColor列敲,只是時間問題而已。
運行這些代碼的話帖汞,我們會看到像下面一樣酷的結果:
3. 理解 State
再看看我們的代碼戴而,其實我們是想傳入一個數(shù)碼寶貝的名字給我們的 Text
view。別忘了翩蘸,我們只有一個簡單的 Struct而已所意,沒有其它神奇的東西。我們前面已經使用過了 Struct鹿鳖,并且在它里面定義過屬性和方法扁眯。
所以,讓我們來定義一個 pokemonName
的屬性和一個改變它的方法:
import SwiftUI
struct ContentView : View {
var pokemonName = "Charmander"
var body: some View {
VStack {
Text(pokemonName)
.frame(
width: UIScreen.main.bounds.width,
height: 50
)
.background(Color.blue)
.foregroundColor(Color.white)
.padding(10)
Button(
action: { self.switchPokemon() },
label: { Text("Switch") }
)
}
}
func switchPokemon() {
pokemonName = "Pikachu"
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Xcode將會報錯: Cannot assign to property: 'self' is inmutable
這是因為 Struct(結構體)默認是不能改變它的屬性的翅帜。它會在 func switchPokemon
方法前面報 mutating
姻檀。但這不是我們的問題 -- 我們只要在 pokemonName
前面加上 @State
關鍵字就解決這問題了!
這個關鍵字是做什么的涝滴?為什么它這么好用呢绣版?
當 State 更新的時候,view將重新校驗UI歼疮,并且更新自身杂抽。
- 從原理上說,我們只要改變了 view 里面被關鍵詞
@State
修飾的屬性韩脏,整個 view 的 body 就會被重新渲染缩麸。
現(xiàn)在讓我們繼續(xù)運行項目,看看視圖里面的 text 是怎樣切換成 pikachu 吧赡矢!
當視圖的 body 第一次渲染出來的時候杭朱,我們是將 “Charmander” 作為 pokemonName
的默認值,而且pokemonName
是被 @State
關鍵字修飾的吹散。所以我們運行后第一時間會看到顯示的是 “Charmander”弧械。
當我們點擊 button,文本將會更新為 “Pikachu”, 因為我們更新的是一個 state 屬性的值空民,所以頁面重新渲染了刃唐,所以這次顯示了 “Pikachu”。
我們可以將 pokemonName
改成隨機的界轩,也就是隨機地更新它的值:
import SwiftUI
struct ContentView : View {
@State var pokemonName = "Charmander"
var body: some View {
VStack {
Text(pokemonName)
.frame(
width: UIScreen.main.bounds.width,
height: 50
)
.background(Color.blue)
.foregroundColor(Color.white)
.padding(10)
Button(
action: { self.switchPokemon() },
label: { Text("Switch") }
)
}
}
func switchPokemon() {
let list = ["Squirtle", "Bulbasaur", "Charmander", "Pikachu"]
pokemonName = list.randomElement() ?? ""
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
現(xiàn)在画饥,你已經完成了這么一個View:它通過修改被 @State
修飾的屬性,就會重新渲染浊猾。
你現(xiàn)在點擊按鈕荒澡,它應該可以隨機切換更新 pokemon name了。