如何禁用NavigationView的推入和弹出动画

34

假设有这样一个简单的 NavigationView

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
            }
        }
    }
}

有人找到了一种方法来禁用NavigationView在将目标视图推入/从堆栈中弹出时的动画吗?

自iOS2.0以来,UIKit就已经实现了这个功能!我认为这对于框架来说并不过分。我尝试了所有视图上的各种修饰符(例如NavigationView容器、目标视图、NavigationLink等)。

这些是我尝试过的一些修饰符:

.animation(nil)

.transition(.identity)

.transaction { t in t.disablesAnimations = true }

.transaction { t in t.animation = nil }

没有任何变化。我在EnvironmentValues中也没有找到任何有用的东西 :-(

我是不是漏掉了什么非常明显的东西,还是这个功能还没有出现?

4个回答

42

Xcode 11.3:

目前没有禁用NavigationView动画的修饰符。

您可以使用结构体init()来禁用动画,代码如下:

struct ContentView : View {

    init(){
        UINavigationBar.setAnimationsEnabled(false)
    }

    var body: some View {
        NavigationView {
            VStack {
                NavigationLink("Push Me", destination: Text("PUSHED VIEW"))
            }
        }
    }
}

2
使用 UINavigationBar.setAnimationsEnabled(false) 似乎是 Xcode 14 和 NavigationStack 的唯一解决方法。 - vicegax

13

iOS & iPadOS 16.2 发布说明

SwiftUI,新功能

  • 通过将路径突变包装在 withTransaction(transaction) { … } 中,并将 transaction 的 disablesAnimations 设置为 true,来禁用 NavigationStack 推送和弹出的动画效果。 (88993253)

早期版本的 iOS

首先,您需要为 NavigationLink 创建一个状态以响应,然后在禁用动画的事务中设置该状态,如下所示:

struct ContentView : View {
    @State var isActive = false
    
    var body: some View {
        NavigationView {
            VStack {
                NavigationLink(isActive: $isActive, destination: {
                    Text("PUSHED VIEW")}) {
                    Text("Push Me")
                }
                Button("Navigate Without Animation") {
                    var transaction = Transaction()
                    transaction.disablesAnimations = true
                    withTransaction(transaction) {
                        isActive = true
                    }
                }
            }
        }
    }
}

@joshuakcockrell 你误导了,我在16.1上测试过了,它是可以工作的。 - gaohomway
@gaohomway 很好。这是一个已报告的错误,他们一定已经修复了。我会删除我的评论。 - joshuakcockrell
1
仅适用于推送动画 - 弹出动画仍然存在。如果您在某处手动将标志设置为false,则也可以将其放入事务块中,但是如果您依赖系统返回按钮,则仍将无法摆脱该动画。 - Greg Ennis

5

我最近创建了一个名为 swiftui-navigation-stackhttps://github.com/biobeats/swiftui-navigation-stack)的开源项目,其中包含 NavigationStackView。这是一个视图,模仿标准的 NavigationView 的导航行为,并添加了一些有用的功能。例如,您可以使用 NavigationStackView 并按照 Kontiki 的问题中请求的方式禁用转换动画。当您创建 NavigationStackView 时,只需将 transitionType 指定为 .none

struct ContentView : View {
    var body: some View {
        NavigationStackView(transitionType: .none) {
            ZStack {
                Color.yellow.edgesIgnoringSafeArea(.all)

                PushView(destination: View2()) {
                    Text("PUSH")
                }
            }
        }
    }
}

struct View2: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            PopView {
                Text("POP")
            }
        }
    }
}

PushViewPopView是两个视图,它们允许您推送和弹出视图(类似于SwiftUI中的NavigationLink)。以下是完整示例:

import SwiftUI
import NavigationStack

struct ContentView : View {
    var body: some View {
        NavigationStackView(transitionType: .none) {
            ZStack {
                Color.yellow.edgesIgnoringSafeArea(.all)

                PushView(destination: View2()) {
                    Text("PUSH")
                }
            }
        }
    }
}

struct View2: View {
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            PopView {
                Text("POP")
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

结果是:

enter image description here

如果你们能加入我一起改进这个开源项目,那就太好了。

0
自从iOS和iPadOS 16.2版本以来,您可以禁用NavigationStack的动画效果,具体操作请参考iOS & iPadOS 16.2 Release Notes
下面的示例展示了在程序中如何在推入或弹出View时禁用动画的可能实现方式:
enum Destination {
    case details
}

import SwiftUI

struct ContentView: View {
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path) {
            Form {
                NavigationLink(value: Destination.details) {
                    Text("Push (with animation)")
                }
                Button("Push (no animation)") {
                    var transaction = Transaction()
                    transaction.disablesAnimations = true
                    withTransaction(transaction) {
                        path.append(Destination.details)
                    }
                }
            }
            .navigationDestination(for: Destination.self) { destination in
                switch destination {
                case .details:
                    DetailsView(path: $path)
                }
            }
        }
    }
}

import SwiftUI

struct DetailsView: View {
    @Binding var path: NavigationPath

    var body: some View {
        Button("Pop (no animation)") {
            var transaction = Transaction()
            transaction.disablesAnimations = true
            withTransaction(transaction) {
                path.removeLast()
            }
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接