SwiftUI中如何为视图宽高设置不同时长的动画?
为SwiftUI视图的宽高设置不同时长的动画
我尝试为SwiftUI视图的宽度和高度设置不同时长的动画,但最终只有一个动画时长生效。请问在给定初始宽高和目标宽高的情况下,该如何实现这一需求?
以下是我尝试过的、本以为可行但实际无效的代码示例:
无效示例1
struct TestView: View { @State var currentWidth: CGFloat = 300 @State var currentHeight: CGFloat = 100 var body: some View { VStack { Color.purple .frame(width:currentWidth, height: currentHeight) .animation(.spring(duration:1.0), value:currentWidth) .animation(.spring(duration:20.0), value:currentHeight) } .onAppear { currentWidth = 450 currentHeight = 900 } } }
无效示例2
struct TestView: View { @State var currentWidth: CGFloat = 300 @State var currentHeight: CGFloat = 100 var body: some View { VStack { Color.purple .frame(width:currentWidth, height: currentHeight) } .onAppear { withAnimation(.spring(duration:1.0)) { currentWidth = 450 } withAnimation(.spring(duration:20.0)) { currentHeight = 900 } } } }
问题原因
- 示例1中,多次调用
.animation会覆盖之前的动画配置,最终只有最后一个绑定的动画生效。 - 示例2中,连续的
withAnimation会被SwiftUI合并为同一个动画事务,导致宽高共享同一段动画时长。
正确实现方式
方法1:拆分视图层级实现独立动画
将宽、高的动画绑定拆分为两个独立的视图层级,确保各自的动画配置不被覆盖:
struct TestView: View { @State var currentWidth: CGFloat = 300 @State var currentHeight: CGFloat = 100 var body: some View { VStack { // 先绑定宽度动画,再嵌套绑定高度动画 Color.purple .frame(width: currentWidth) .animation(.spring(duration: 1.0), value: currentWidth) .frame(height: currentHeight) .animation(.spring(duration: 20.0), value: currentHeight) } .onAppear { currentWidth = 450 currentHeight = 900 } } }
方法2:异步分离动画事务
通过极小的异步延迟,让两个withAnimation事务不被合并:
struct TestView: View { @State var currentWidth: CGFloat = 300 @State var currentHeight: CGFloat = 100 var body: some View { VStack { Color.purple .frame(width: currentWidth, height: currentHeight) } .onAppear { withAnimation(.spring(duration: 1.0)) { currentWidth = 450 } // 用极小延迟拆分动画事务 DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) { withAnimation(.spring(duration: 20.0)) { currentHeight = 900 } } } } }
推荐使用方法1,它通过视图层级的天然隔离保证动画独立性,无需依赖异步延迟的hack手段。
内容的提问来源于stack exchange,提问作者AntcDev
相关产品推荐
相关产品推荐

