@Status
通过使用 @State 修饰器我们可以关联出 View 的状态. SwiftUI 将会把使用过 @State 修饰器的属性存储到一个特殊的内存区域,并且这个区域和 View struct 是隔离的. 当 @State 装饰过的属性发生了变化,SwiftUI 会根据新的属性值重新创建视图
struct ContentView: View {
@State var score = 0
var body: some View {
VStack {
Text("Your score is \(score)")
Button(action: {
self.score += 1
}) {
Text("Increase Score")
}
}
}
}
@Binding
有时候我们会把一个视图的属性传至子节点中,但是又不能直接的传递给子节点,因为在 Swift 中值的传递形式是值类型传递方式,也就是传递给子节点的是一个拷贝过的值。但是通过 @Binding 修饰器修饰后,属性变成了一个引用类型,传递变成了引用传递,这样父子视图的状态就能关联起来了。
struct ContentView: View {
@State var score = 0
@State var isShowActivity = false
var body: some View {
VStack {
Text("Your score is \(score)")
Button(action: {
self.score += 1
}) {
Text("Increase Score")
}
TestView(isShowActivity: $isShowActivity)
if isShowActivity {
Text("TestView")
}
}
}
}
struct TestView: View {
@Binding var isShowActivity:Bool
var body: some View {
HStack {
Toggle(isOn: $isShowActivity) {
Text("Change isShowActivity")
}
}
}
}
@ObservedObject
@ObservedObject 的用处和 @State 非常相似,从名字看来它是来修饰一个对象的,这个对象可以给多个独立的 View 使用。如果你用 @ObservedObject 来修饰一个对象,那么那个对象必须要实现 ObservableObject 协议,然后用 @Published 修饰对象里属性,表示这个属性是需要被 SwiftUI 监听的
struct ContentView: View {
@ObservedObject var settings = UserSettings()
@State var isShowActivity = false
var body: some View {
VStack {
Text("Your score is \(settings.score)")
Button(action: {
self.settings.score += 1
}) {
Text("Increase Score")
}
TestView(isShowActivity: $isShowActivity)
if isShowActivity {
Text("TestView")
}
}
}
}
struct TestView: View {
@Binding var isShowActivity:Bool
var body: some View {
HStack {
Toggle(isOn: $isShowActivity) {
Text("Change isShowActivity")
}
}
}
}
class UserSettings: ObservableObject {
@Published var score = 0
}
@EnvironmentObject
从名字上可以看出,这个修饰器是针对全局环境的。通过它,我们可以避免在初始 View 时创建 ObservableObject, 而是从环境中获取 ObservableObject
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView().environmentObject(UserData())
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
}
ContentView.swift
struct ContentView: View {
@ObservedObject var settings = UserSettings()
@EnvironmentObject var userData: UserData
@State var isShowActivity = false
var body: some View {
VStack {
Text("Your score is \(settings.score)")
Button(action: {
self.settings.score += 1
self.userData.isShowActivity = !self.userData.isShowActivity
}) {
Text("Increase Score")
}
if userData.isShowActivity {
Text("TestView")
}
TestView()
}
}
}
struct TestView: View {
@EnvironmentObject var userData: UserData
var body: some View {
HStack {
if userData.isShowActivity {
Text("Change isShowActivity")
}
}
}
}
class UserSettings: ObservableObject {
@Published var score = 0
}
final class UserData: ObservableObject {
@Published var isShowActivity = false
}