最近有个群友询问自己的ZStack动画效果有问题。于是帮其进行了分析,最终解决了问题。
在 SwiftUI 中,最简单、最快捷的方法之一是使用条件 ZStack。然而,在尝试制作 in-out 过渡的动画时,in 动画效果很好,但 out 动画效果不佳。让我们检查一下问题,然后找到解决方案。
以下面的代码为例:
struct ContentView: View {
//State that stores the blue rectangle show state
@State var showBlue = false
var body: some View {
ZStack{
//Green rectangle
Rectangle()
.frame(width: 200, height: 200)
.foregroundColor(.green)
//Blue rectangle - Conditional!
if showBlue{
Rectangle()
.frame(width: 200, height: 200)
.foregroundColor(.blue)
.transition(.opacity)
}
//Button that shows/hides the blue rectangle
Button("showBlue") {
withAnimation{
showBlue.toggle()
}
}.foregroundColor(.white)
}
}
}
让我们尝试运行该应用程序。如果按下 showBlue 按钮,您将看到蓝色矩形将显示为动画并且效果很好。但是如果你再次切换它,蓝色矩形就会消失,没有任何动画。什么原因会导致此问题?
问题在于 ZStack。每次 showBlue 状态更改时,SwiftUI 都会重新渲染 ContentView 结构体。当将其设置为 true 时,它会重新渲染视图,添加蓝色矩形,然后动画将发生。当再次按下按钮时,也会发生同样的情况。showBlue 将更改为 false,ContentView 视图结构将重新渲染,现在没有蓝色矩形。不过,动画应该开始,并且不透明度应该降低到 0。问题是,第二次重新渲染视图时,ZStack 会以不合适的方式发生变化。蓝色的矩形将从 ZStack 中取出,被按钮所替换。zIndex 定义视图在 ZStack 中如何相互对齐。zIndex 在 ZStack 中自动计算。例如,如果蓝色矩形可见,则绿色将变为 1,蓝色变为 2,按钮将变为 3。索引越大,视图越靠前。所以蓝色矩形在绿色矩形的上方,绿色矩形在蓝色矩形的后面。该按钮位于蓝色矩形上方,依此类推......当视图重新呈现时,按钮的 zIndex 将从 3 更改为 2。它替换了蓝色的矩形(以前有 zIndex 2),因此动画无法正常发生。
要解决此问题,需要做的就是手动指定 zIndex。如果这样做,则按钮将保持在 zIndex 3 处,因此它不会替换蓝色的矩形。这样,也可以发生过渡出动画。让我们尝试实现修复:
struct ContentView: View {
//State that stores the blue rectangle show state
@State var showBlue = false
var body: some View {
ZStack{
//Green rectangle
Rectangle()
.frame(width: 200, height: 200)
.foregroundColor(.green)
.zIndex(1)
//Blue rectangle - Conditional!
if showBlue{
Rectangle()
.frame(width: 200, height: 200)
.foregroundColor(.blue)
.transition(.opacity)
.zIndex(2)
}
//Button that shows/hides the blue rectangle
Button("showBlue") {
withAnimation{
showBlue.toggle()
}
}.foregroundColor(.white)
.zIndex(3)
}
}
}
现在运行动画,它将正常工作。我希望本教程能帮助您理解和解决 ZStack 中的过渡动画相关问题。
参考
SwiftUI — How to solve transition animation problems in ZStack