You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 14:52:05