SwiftUI按钮:如何在按压动画完成后执行跳转动作?
解决方案:等待按钮动画完成后再执行跳转
要解决按钮点击后直接跳转导致看不到按压动画的问题,核心思路是让跳转动作延迟到动画完成后执行,下面提供两种可行实现方式:
方法一:固定延迟匹配动画时长
先给自定义按钮样式明确动画时长,再通过DispatchQueue延迟对应时间执行跳转:
1. 修改自定义按钮样式(明确动画时长)
struct CustomButtonStyle: ButtonStyle { func makeBody(configuration: Configuration) -> some View { configuration.label .foregroundColor(Color.blue) .padding(.vertical) .frame(height: 48) .frame(minWidth: 0, maxWidth: .infinity, alignment: .center) .background(Color.white) .cornerRadius(32) .scaleEffect(configuration.isPressed ? 0.9 : 1.0) .opacity(configuration.isPressed ? 0.6 : 1.0) // 明确动画时长,后续延迟时间和这个保持一致 .animation(.easeInOut(duration: 0.2), value: configuration.isPressed) } }
2. 在视图中添加延迟跳转逻辑
struct TestView: View { @State private var navigationPath = NavigationPath() var body: some View { NavigationStack(path: $navigationPath) { Button(action: { // 延迟0.2秒,确保动画完全结束后再跳转 DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { navigationPath.append("TargetView") } }, label: { Text("Test") }) .buttonStyle(CustomButtonStyle()) .navigationDestination(for: String.self) { _ in // 替换成你的目标视图 Text("Next View") } } } }
方法二:利用动画完成回调(更精准)
通过SwiftUI的动画完成回调,在缩放/透明度动画结束后触发跳转,无需依赖固定延迟:
struct TestView: View { @State private var navigationPath = NavigationPath() @State private var isButtonPressed = false var body: some View { NavigationStack(path: $navigationPath) { Button(action: { isButtonPressed = true // 执行按压恢复动画,完成后触发跳转 withAnimation(.easeInOut(duration: 0.2)) { isButtonPressed = false } completion: { navigationPath.append("TargetView") } }, label: { Text("Test") .foregroundColor(Color.blue) .padding(.vertical) .frame(height: 48) .frame(minWidth: 0, maxWidth: .infinity, alignment: .center) .background(Color.white) .cornerRadius(32) .scaleEffect(isButtonPressed ? 0.9 : 1.0) .opacity(isButtonPressed ? 0.6 : 1.0) }) .navigationDestination(for: String.self) { _ in Text("Next View") } } } }
两种方法对比
- 方法一:实现简单,无需改动原有
ButtonStyle结构,但动画时长修改时需要同步调整延迟时间。 - 方法二:动画完成时机判断更精准,避免固定延迟的误差,但需要将样式逻辑从
ButtonStyle移到视图层级(或通过状态传递给ButtonStyle)。
如果使用的是NavigationLink而非NavigationStack,只需将跳转逻辑替换为激活NavigationLink的绑定状态即可,核心思路一致。
内容的提问来源于stack exchange,提问作者user45723
相关产品推荐
相关产品推荐

