有什么方法可以判断哪个状态更改导致在 SwiftUI 中重建视图?
Is there any way to tell which state change caused the view to be rebuilt in SwiftUI?
我有一个视图需要像手风琴一样工作,用户可以在其中拖动以打开/折叠它。我希望它在用户拖动时没有任何动画,但在他离开时有动画。所以,我想在我的视图中有两个状态变量(比如高度和 tempHeight),但我只会在高度变量触发视图重建过程时设置动画。
拖动时高度和 tempHeight 变化的动画看起来很奇怪,感觉有延迟。
描述我的问题的示例代码:
struct ContentView: View {
@State var tempHeight: CGFloat = 200
@State var height: CGFloat = 200
var dragGesture: some Gesture {
DragGesture(),
.onChanged { value in
tempHeight = min(400, max(200, height + value.translation.height))
}
.onEnded { value in
height = tempHeight > 300 ? 400 : 200
tempHeight = height
}
}
var body: some View {
VStack {
Spacer()
.frame(height: 100)
Color.blue.frame(height: tempHeight)
.animation(.easeIn)
.gesture(dragGesture)
Spacer()
}
}
}
我试图解决这个问题的方法是拥有一个静态变量,它跟踪最后发生的状态变化并且它似乎有效。
我当前的解决方法:
enum StateChange {
case height
case tempHeight
static var lastChangeBy: StateChange = .height
}
struct ContentView: View {
@State var tempHeight: CGFloat = 200
@State var height: CGFloat = 200
var dragGesture: some Gesture {
DragGesture()
.onChanged { value in
tempHeight = min(400, max(200, height + value.translation.height))
StateChange.lastChangeBy = .tempHeight
}
.onEnded { value in
height = tempHeight > 300 ? 400 : 200
tempHeight = height
StateChange.lastChangeBy = .height
}
}
var body: some View {
VStack {
Spacer()
.frame(height: 100)
Color.blue.frame(height: tempHeight)
.gesture(dragGesture)
.animation(StateChange.lastChangeBy == .height ? .easeInOut : .none)
.animation(.easeInOut)
Spacer()
}
}
}
这对我来说就像是一个 hack。如果我有很多 @State 包装变量,它很快就会变得一团糟。是否有可能知道哪个状态变化会触发在体内构建视图,以便我可以有条件地将动画应用于特定触发器或更好的编写方式。
您可以在修改器中明确指定哪些值更改会激活动画,例如
Color.blue.frame(height: tempHeight)
.gesture(dragGesture)
.animation(.easeInOut, value: height) // << here
我有一个视图需要像手风琴一样工作,用户可以在其中拖动以打开/折叠它。我希望它在用户拖动时没有任何动画,但在他离开时有动画。所以,我想在我的视图中有两个状态变量(比如高度和 tempHeight),但我只会在高度变量触发视图重建过程时设置动画。
拖动时高度和 tempHeight 变化的动画看起来很奇怪,感觉有延迟。
描述我的问题的示例代码:
struct ContentView: View {
@State var tempHeight: CGFloat = 200
@State var height: CGFloat = 200
var dragGesture: some Gesture {
DragGesture(),
.onChanged { value in
tempHeight = min(400, max(200, height + value.translation.height))
}
.onEnded { value in
height = tempHeight > 300 ? 400 : 200
tempHeight = height
}
}
var body: some View {
VStack {
Spacer()
.frame(height: 100)
Color.blue.frame(height: tempHeight)
.animation(.easeIn)
.gesture(dragGesture)
Spacer()
}
}
}
我试图解决这个问题的方法是拥有一个静态变量,它跟踪最后发生的状态变化并且它似乎有效。 我当前的解决方法:
enum StateChange {
case height
case tempHeight
static var lastChangeBy: StateChange = .height
}
struct ContentView: View {
@State var tempHeight: CGFloat = 200
@State var height: CGFloat = 200
var dragGesture: some Gesture {
DragGesture()
.onChanged { value in
tempHeight = min(400, max(200, height + value.translation.height))
StateChange.lastChangeBy = .tempHeight
}
.onEnded { value in
height = tempHeight > 300 ? 400 : 200
tempHeight = height
StateChange.lastChangeBy = .height
}
}
var body: some View {
VStack {
Spacer()
.frame(height: 100)
Color.blue.frame(height: tempHeight)
.gesture(dragGesture)
.animation(StateChange.lastChangeBy == .height ? .easeInOut : .none)
.animation(.easeInOut)
Spacer()
}
}
}
这对我来说就像是一个 hack。如果我有很多 @State 包装变量,它很快就会变得一团糟。是否有可能知道哪个状态变化会触发在体内构建视图,以便我可以有条件地将动画应用于特定触发器或更好的编写方式。
您可以在修改器中明确指定哪些值更改会激活动画,例如
Color.blue.frame(height: tempHeight)
.gesture(dragGesture)
.animation(.easeInOut, value: height) // << here