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

SwiftUI视图动画过渡异常:Red→Green跳转不符合预期

SwiftUI导航动画问题分析与修复

问题原因

  1. 过渡动画方向定义错误
    你定义的forwardTransition中,旧视图的移除动画用了.move(edge: .trailing),这会让旧视图向右滑走,但你期望的是旧视图向左滑出。同时backTransition的移除方向也不符合返回逻辑的需求。

  2. navForward未被SwiftUI监听
    Router中的navForward是普通变量,不是@Published属性,SwiftUI无法感知它的变化,导致视图切换时过渡动画的方向无法及时更新。

  3. 动画依赖单一
    当前动画仅依赖currentScreen,但过渡方向由navForward决定,两者变化不同步时会导致动画方向错误。

修复方案

1. 修正Router的navForward属性

将navForward改为@Published,让SwiftUI监听其变化:

enum Screen : Equatable {
    case blue
    case red
    case green
}

class Router: ObservableObject {
    public static let shared = Router()

    @Published var currentScreen: Screen = .blue
    @Published var previousScreen: Screen = .blue
    @Published var navForward: Bool = false // 改为@Published

    func goToScreen(screen: Screen) {
        previousScreen = currentScreen
        currentScreen = screen
    }
}

2. 重新定义过渡动画

调整forwardTransition和backTransition的插入/移除方向,匹配你的需求:

  • 前进(Blue→Red→Green):新视图从右侧滑入,旧视图向左滑出
  • 返回(Green→Red→Blue):新视图从左侧滑入,旧视图向右滑出
extension AnyTransition {       
    static var forwardTransition: AnyTransition {
        .asymmetric(
            insertion: .move(edge: .trailing).combined(with: .opacity), // 新视图从右侧进入
            removal: .move(edge: .leading).combined(with: .opacity)    // 旧视图向左退出
        )
    }
    
    static var backTransition: AnyTransition {
        .asymmetric(
            insertion: .move(edge: .leading).combined(with: .opacity),  // 新视图从左侧进入
            removal: .move(edge: .trailing).combined(with: .opacity)    // 旧视图向右退出
        )
    }
}

3. 更新动画依赖

让动画同时监听currentScreen和navForward,确保过渡方向和视图切换同步:

@main
struct RouterAnimationApp: App {
    @ObservedObject var router = Router.shared

    var body: some Scene {
        WindowGroup {
            ZStack {
                VStack {
                    switch(router.currentScreen) {
                    case .red:
                        RedView()
                            .transition(router.navForward ? .forwardTransition : .backTransition)
                    case .blue:
                        BlueView()
                            .transition(router.navForward ? .forwardTransition : .backTransition)
                    case .green:
                        GreenView()
                            .transition(router.navForward ? .forwardTransition : .backTransition)
                    }
                }
                .animation(.easeInOut(duration: 1.0), value: [router.currentScreen, router.navForward])

                VStack {
                    Button(action: {
                        router.navForward = true
                        router.goToScreen(screen: .red)
                    }, label: {
                        Text("blue to red")
                    })
                    Button(action: {
                        router.navForward = true
                        router.goToScreen(screen: .green)
                    }, label: {
                        Text("red to green")
                    })
                    Button(action: {
                        router.navForward = false
                        router.goToScreen(screen: .red)
                    }, label: {
                        Text("green to red")
                    })
                    Button(action: {
                        router.navForward = false
                        router.goToScreen(screen: .blue)
                    }, label: {
                        Text("red to blue")
                    })
                }
                .foregroundColor(.white)
            }
        }
    }
}

效果验证

  • 前进操作(Blue→Red→Green):旧视图向左滑出,新视图从右侧滑入,符合预期
  • 返回操作(Green→Red→Blue):旧视图向右滑出,新视图从左侧滑入,符合返回逻辑

内容的提问来源于stack exchange,提问作者soleil

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 21:45:29