SwiftUI 学习 - @State,@Binding,@St
2022-07-14 本文已影响0人
songzi
为了让数据更新后,自动更新画面,需要用到一些特殊的修饰符。
@State
@State,一般用于修饰本画面内部的私有属性(private)。这些私有属性的生命周期和本画面一致。属性的初始化,修改等操作,都是在本画面内完成,并不希望其他画面去碰这些数据,但这个画面的子画面除外。
struct ContentView: View {
@State private var isFavorite = false
var body: some View {
HStack {
Text("Click The Star")
Button {
isFavorite.toggle()
} label: {
Label("Change Favorite", systemImage: isFavorite ? "star.fill" : "star")
.labelStyle(.iconOnly)
.foregroundColor(isFavorite ? .yellow : .gray)
}
}
}
}
@Binding
@Binding,一般用于修饰引用父画面的属性为自己所用,并且修改后能反馈给父画面。
struct ContentView: View {
@State private var isFavorite : Bool = false
var body: some View {
VStack {
HStack {
Text("Click The Star In Me")
Button {
isFavorite.toggle()
} label: {
Label("Change Favorite", systemImage: isFavorite ? "star.fill" : "star")
.labelStyle(.iconOnly)
.foregroundColor(isFavorite ? .yellow : .gray)
}
}
ContentSubView(isFavorite: $isFavorite).padding()
}
}
}
struct ContentSubView: View {
@Binding var isFavorite : Bool
var body: some View {
HStack {
Text("Click The Star In SubView")
Button {
isFavorite.toggle()
} label: {
Label("Change Favorite", systemImage: isFavorite ? "star.fill" : "star")
.labelStyle(.iconOnly)
.foregroundColor(isFavorite ? .yellow : .gray)
}
}
}
}
ContentView 和 ContentSubView 的 isFavorite 是完全同步的。但是 ContentSubView 中的 isFavorite 是从 ContentView 传来的,而且必须使用 $isFavorite 这种写法。
@StateObject
和@State类似,用于修饰继承了ObservableObject 协议的对象。
final class User: ObservableObject {
@Published var name = ""
init(name: String) {
self.name = name
}
}
struct ContentView: View {
@StateObject private var user: User = User(name: "Jacky Liu")
var body: some View {
VStack {
HStack {
Text(user.name)
Button {
user.name = "Linda"
} label: {
Text("Change Name")
}
}
}
}
}
@EnvironmentObject
@EnvironmentObject,是引用环境中的继承了ObservableObject 协议的对象为自己所用,使用 view 的 environmentObject 函数,将对象放入环境中。
final class User: ObservableObject {
@Published var name = ""
init(name: String) {
self.name = name
}
}
struct ContentView: View {
@EnvironmentObject var user: User
var body: some View {
VStack {
HStack {
Text(user.name)
Button {
user.name = "Linda"
} label: {
Text("Change Name")
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(User(name: "Jack Liu"))
}
}
@ObservedObject
@ObservedObject,一般用于修饰引用其他画面的继承了ObservableObject 协议的对象为自己所用,并且修改后能反馈给其他画面。
final class User: ObservableObject {
@Published var name = ""
init(name: String) {
self.name = name
}
}
struct ContentView: View {
@StateObject var user: User = User(name: "Jacky Liu")
var body: some View {
VStack {
HStack {
Text(user.name)
Button {
user.name = "Linda"
} label: {
Text("Change Name")
}
}
ContentSubView(user: self.user).padding()
}
}
}
struct ContentSubView: View {
@ObservedObject var user: User
var body: some View {
HStack {
Text(user.name)
Button {
user.name = "Linda"
} label: {
Text("Change Name In Subview")
}
}
}
}
总结:
- @State,@Binding,主要用于修饰简单类型,比如Bool, String, Struct等。
- @StateObject,@EnvironmentObject,@ObservedObject,主要用于修饰继承了ObservableObject 协议的对象。
- @State, @StateObject修饰的属性,是与本画面的生命周期完全一致,@Binding,@EnvironmentObject,@ObservedObject修饰的属性并不能保证与本画面的生命周期一致,有可能属性已经在其他画面被销毁了。
- 只要在某个画面中把对象加入环境中,其他画面都可以使用@EnvironmentObject来引用该对象,比如数据中心的设计模式。
- @State,@Binding,@StateObject,@ObservedObject,只能根据画面的层次进行传递属性。比如画面A->B->C,C想使用A的属性,就必须让A先把属性给B,然后再让B把属性给C,才能达到目的。
(未完待续)