我正在尝试使用 SwiftUI 来更好地理解它,但我无法理解这种行为上的差异。在此示例代码中,为什么结构视图能够旋转而 @ViewBuilder 函数却不能旋转?
struct ContentView: View {
@State var isSpinning = false
var body: some View {
StructView()
funcView()
}
@ViewBuilder
func funcView() -> some View {
@State var isSpinning = false
VStack {
Button {
isSpinning.toggle()
}label: {
Text("Spin me")
}
Image(systemName: "arrow.clockwise")
.font(.system(size: 80))
.foregroundColor(.blue)
.rotationEffect(.degrees(isSpinning ? 360 : 0))
.animation(.easeInOut(duration: 1), value: isSpinning)
}
.padding()
}
struct StructView: View {
@State var isSpinning = false
var body: some View {
VStack {
Button {
isSpinning.toggle()
}label: {
Text("Spin me")
}
Image(systemName: "arrow.clockwise")
.font(.system(size: 80))
.foregroundColor(.blue)
.rotationEffect(.degrees(isSpinning ? 360 : 0))
.animation(.easeInOut(duration: 1), value: isSpinning)
}
.padding()
}
}
}
它是否是一个
@ViewBuilder
函数,或者它是否是一个单独的函数,对于 SwiftUI 来说并不重要。这和你将其内联funcView
并直接放入是一样的body
。问题在于,它
@State
不能作为局部变量使用。SwiftUI 并非设计用于跟踪@State
局部变量。s应始终在结构体中@State
声明为实例属性View
。在您的代码中,您也这样做了。您
@State var isSpinning = false
直接在 中声明ContentView
,但又在 中声明funcView
,因此对isSpinning
中的引用funcView
全部解析为@State
在 中声明的funcView
。@State var isSpinning = false
您应该删除中的行funcView
,现在对的引用isSpinning
将解析为中声明的行ContentView
,并且视图将按预期工作。请注意,写入所有内容(调用资金/属性实际上等同于此)和将视图组件分成不同的结构之间存在差异。
body
@ViewBuilder
View
通过将内容放入单独的
View
结构中,您可以有效地为视图更新创建“屏障”。例如,StructView.body
不会在每次发生ContentView
更改时调用,因为StructView
它不依赖于中的任何内容ContentView
。另一方面,每次 中有所变化时
funcView
都会ContentView
被调用,因为您实际上是在 中调用它ContentView.body
。View
因此,一般来说,将视图分成单独的结构体比将视图分成单独的@ViewBuilder func
s 或@ViewBuilder var
同一结构体中的 s要好View
。这样,视图层次结构顶部的更新不会导致其他所有内容也更新。这里我添加了一些
print
来演示差异: