我們在大部分的手機 App 中,都會看到整個 App 和視圖之間共享數據 (data) 的情況。SwiftUI 提供了一個方便又簡單的方法,讓我們在 App 中傳遞數據。在這篇文章中,我們將會試著使用 @EnvironmentObject,並仔細研究它的行為。
@EnvironmentObject 是一種物件型別 (object type),讓我們可以添加數據,之後再利用@StateObject 在 App 中隨時存取它,來添加信息或作出修改。
在這篇文章中,我將會利用一個簡單的例子,來示範如何使用 @EnvironmentObject 來傳遞數據。在這個範例中,我們會定義:
- UserSettings 類別,它包含了兩個 @published 屬性 (property):setting 和 userRole。
- ViewSettings 視圖,用來在 Environment 接收 UserSetting 物件,並顯示 User Setting。
- ContentView 視圖,用來建立 UserSettings 物件,我們可以利用分段控制器 (segmented control) 來改變 User Settings。
以下是 UserSettings 的程式碼:
import Foundation
class UserSettings: ObservableObject {
@Published var setting = 0
@Published var userRole = 0
}
在上面的程式碼中,我們建立了一個符合 ObservableObject 的類別,及設定的數值,我們之後會在 App 中發佈和修改它們。
以下是 ViewSettings 的程式碼:
import Foundation
import SwiftUI
struct ViewSettings: View {
@EnvironmentObject var settings: UserSettings
var body: some View {
Text("\(settings.userRole == 0 ? "User" : "Admin") is \(settings.setting == 0 ? "Active" : "Inactive" )")
}
}
ViewSetting 視圖會利用 @EnvironmentObject 存取 UserSettings 類別,並使用它的屬性。
以下是 ContentView 的程式碼:
struct ContentView: View {
@StateObject var settings = UserSettings()
@State private var settingsTag = 0
@State private var roleSettingsTag = 0
@State private var active = "InActive"
@State private var userRole = "User"
@State private var selection = 2
@State private var roleSelection = 1
init() {
UISegmentedControl.appearance().selectedSegmentTintColor = .systemPink
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor.systemPink], for: .normal)
}
var body: some View {
NavigationView {
VStack {
Picker("", selection: $settingsTag){
Text("Active").tag(0)
Text("InActive").tag(1)
}.onChange(of: settingsTag){_ in
settings.setting = settingsTag
}
.padding()
.pickerStyle(SegmentedPickerStyle())
Text("\(settingsTag)")
Divider()
.frame(height: 1)
Picker("", selection: $roleSettingsTag){
Text("User").tag(0)
Text("Admin").tag(1)
}
.onChange(of: roleSettingsTag){_ in
settings.userRole = roleSettingsTag
}
.padding()
.pickerStyle(SegmentedPickerStyle())
Text("\(roleSettingsTag)")
Button(action: {
print(settings.setting)
print(settings.userRole)
}) {
NavigationLink(destination: ViewSettings()) {
Text("View Settings")
.padding()
.foregroundColor(.white)
.background(Color.pink)
.cornerRadius(5)
.padding(.top, 30)
}
}
}
}.environmentObject(settings)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
以上的程式碼是範例的主視圖,也就是我們施展魔術的地方。
添加了以上的程式碼之後,主視圖看起來會是這樣:
讓我簡單總結一下這個 App 的功能。我們宣告了 @StateObject 型別的 Settings 變數,我們會利用這個變數來修改和傳遞數據。來看看 onChange event 屬性,我們會在分段控制器中分配數值,而這些改動會被保存在 Settings 物件中。最重要的是,我們必須在父視圖 (parent view) 中添加 environmentObject,並添加想要設為 Environment Object 的物件;在我們這個範例中,就是 settings 變數。
在 View Settings 按鈕中,我們添加了導航連結 (link) 鏈接到下一個螢幕,在導航的時候,就能夠存取我們在 ViewSettings 視圖中修改後的數據。
完成了!我們成功把數據從 ContentView 視圖傳遞到 ViewSettings 視圖了。你可以在 GitHub 參考完整的程式碼。