我有一个 SwiftUI 视图,它针对不同的界面方向具有不同的布局。我使用类似的东西来实现它(只是为了最小化可重现的示例代码,我在下面包含了一个示例代码)。
import SwiftUI
struct ContentView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.verticalSizeClass) private var verticalSizeClass
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
var body: some View {
ZStack(content: {
if verticalSizeClass == .regular {
testView
} else {
testView
}
})
}
var testView: some View {
TestView()
}
}
struct TestView: View {
@State var isSelected = false
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
.overlay {
if isSelected {
RoundedRectangle(cornerRadius: 5)
.stroke(.yellow, lineWidth: 3.0)
}
}
.gesture(
TapGesture(count: 1)
.onEnded({ _ in
isSelected.toggle()
})
)
}
}
在自动旋转时,SwiftUI 会将
TestView
视为具有不同身份的单独视图,因此该视图将丢失其当前状态(上例中的 isSelected
)并将被重新绘制为新的视图。
解决此类问题的正确方法是什么?是否可以为各个子视图分配身份,以便它们保留自动旋转的状态?因为在原来的项目中,两个方向都有很多共同的子视图。
在 testView 内部移动不同方向的尺寸类环境值和逻辑,因此 testView 在方向变化时将具有相同的标识,并且方向更新仅发生在 testView 内部。
struct ContentView: View {
@Environment(\.dismiss) private var dismiss
var body: some View {
ZStack(content: {
testView
})
}
var testView: some View {
TestView()
}
}
struct TestView: View {
@State var isSelected = false
@Environment(\.verticalSizeClass) private var verticalSizeClass
@Environment(\.horizontalSizeClass) private var horizontalSizeClass
var body: some View {
VStack {
if verticalSizeClass == .regular {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
} else {
HStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.transition(.scale)
}
}
.padding()
.overlay {
if isSelected {
RoundedRectangle(cornerRadius: 5)
.stroke(.yellow, lineWidth: 3.0)
}
}
.gesture(
TapGesture(count: 1)
.onEnded({ _ in
isSelected.toggle()
})
)
}
}