在SwiftUI中,@State和@Binding是用于管理视图状态和数据流的重要属性包装器。
@State
@State是一个属性包装器,用于在视图中管理可变的局部状态。通过将属性标记为@State,您可以使该属性与视图的生命周期相关联,并在属性值更改时自动更新视图。当使用@State标记属性时,SwiftUI会负责在视图层次结构发生更改时自动刷新相关部分的视图。
下图为一个简单的例子,点击按钮来更改背景色和按钮的文字。
左侧为初始化状态,右侧是已点击状态
struct StateAndBindingSample: View {
@State var backgroundColor: Color = .mint
@State var title: String = "未点击"
var body: some View {
ZStack {
backgroundColor
.edgesIgnoringSafeArea(.all)
Button {
backgroundColor = Color.yellow
title = "已完成"
} label: {
Text(title)
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(Color.white)
.padding()
.padding(.horizontal)
.background(Color.black)
.cornerRadius(10)
}
}
}
}
这是一个简单的例子,那么在实际开发中,往往会有很多代码。此时我们不可能还是写在一个方法里面,我们会把功能按照模块划分,多处使用的代码会封装在一个方法里面,多处使用的UI会做成组件等。
我们现在的需求还是点击按钮更换父类的背景色,我们现在把这个代码重构一下,把button的代码部分提取成一个类来管理
我们先把option键按住,点击鼠标Button,此时会出现一个Extract Subview,点击后buttong部分的代码就会被提取成一个组件,我们命名为ButtonView。
但是你会发现,此时有问题了。因为backgroundColor和title属性在父类里面,而现在自定义的ButtonView不能访问。
另外title可以从父类移动到自定义的ButtonView,因为它只是在ButtonView里面使用title,并未和外界有关联。有关联的部分是当我们点击Button来改变父类的背景色。 那么我们改如何来实现了?此时我们就要使用 @binding来完成这个任务
我们把title移入到ButtonView里面
struct StateAndBindingSample: View {
@State var backgroundColor: Color = .mint
var body: some View {
ZStack {
backgroundColor
.edgesIgnoringSafeArea(.all)
ButtonView()
}
}
}
struct StateAndBindingSample_Previews: PreviewProvider {
static var previews: some View {
StateAndBindingSample()
}
}
struct ButtonView: View {
@State var title: String = "未点击"
var body: some View {
Button {
backgroundColor = Color.yellow
title = "已完成"
} label: {
Text(title)
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(Color.white)
.padding()
.padding(.horizontal)
.background(Color.black)
.cornerRadius(10)
}
}
}
@Binding
@Binding用于在不同视图之间创建双向绑定,使它们共享和同步相同的数据。通过将属性标记为@Binding,您可以传递数据的引用,并确保对该数据的更改在源视图和目标视图之间保持同步
struct StateAndBindingSample: View {
@State var backgroundColor: Color = .mint
var body: some View {
ZStack {
backgroundColor
.edgesIgnoringSafeArea(.all)
ButtonView(backgroundColor: $backgroundColor)
}
}
}
struct StateAndBindingSample_Previews: PreviewProvider {
static var previews: some View {
StateAndBindingSample()
}
}
struct ButtonView: View {
@Binding var backgroundColor: Color
@State var title: String = "未点击"
var body: some View {
Button {
backgroundColor = Color.yellow
title = "已完成"
} label: {
Text(title)
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(Color.white)
.padding()
.padding(.horizontal)
.background(Color.black)
.cornerRadius(10)
}
}
}
在上述示例中, StateAndBindingSample 拥有一个 backgroundColor 的 @State 属性,用于控制是否显示 StateAndBindingSample 的背景色,通过接受 backgroundColor 的 @Binding 属性,与 StateAndBindingSample 的 backgroundColor 进行双向绑定。当 ButtonView 中的按钮被点击时,backgroundColor 的值会更新,并将 更改传递回StateAndBindingSample,从而更新视图状态。
需要注意的是,我们在 父类往子类传递变量进行绑定时,需要使用$,美元符号来修饰,要进行双向绑定的变量。如果只是正常传递数据,那么就不需要$符号