为什么清除新的 iOS 16 SwiftUI NavigationPath 到“弹出到根目录”时不能平滑地返回到根视图?

Mgw*_*gwd 25 swiftui ios16 xcode14 swiftui-navigationstack

我有一个新的 iOS 16 SwiftUI NavigationStack,其导航由 NavigationDestination 修饰符确定,效果很好。

我的问题是,如果您在堆栈深处有多个视图,那么在清除 NavigationPath 时,为什么它不能通过滑回根视图来平滑地进行动画处理?

如果您只有一层深度,它会起作用,但任何低于该深度的内容都会导致“弹出到根”仅跳回到根视图而没有滑动动画。

这是一个“功能”还是错误,还是我做错了什么?

重新创建问题的步骤

  • 运行下面的示例代码。
  • 单击第一个导航链接,然后单击“弹出到根视图” - 请注意,它“平滑地”滑回到根视图。
  • 单击第一个或第二个链接 - 然后单击显示视图 3 的“导航到视图 3”。
  • 然后单击“Pop to Root”,您会注意到它跳回到根视图而不是幻灯片。这就是我的问题——它应该跳回来还是滑回来?

发行演示

在此输入图像描述

演示代码(使用 Xcode 14.0 和 iOS 16.0):

import SwiftUI
struct DemoPop: View {

    @State private var path = NavigationPath()
    
    var body: some View {
        
        VStack {
            
            NavigationStack(path: $path) {
                   
                List {
                    Section("List One") {
                        NavigationLink("Navigate to View 1", value: "View 1")
                        NavigationLink("Navigate to View 2", value: "View 2")
                    }
                }
                .navigationDestination(for: String.self) { textDesc in
                    
                    VStack {
                        Text(textDesc).padding()
                        Button("Navigate to View 3") {
                            path.append("View 3")
                        }.padding()
                        
                        Button("Pop to Root View") {
                            path.removeLast(path.count)
                        }.padding()
                    }
                }
                .navigationTitle("Test Pop To Root")
            }
        }
    }
}
    

struct DemoPop_Previews: PreviewProvider {
    static var previews: some View {
        DemoPop()
    }
}
Run Code Online (Sandbox Code Playgroud)

更新1:

认为上面的代码是正确的,所以可能是评论中提到的错误,因为我刚刚看到了一个表现出相同行为的 YouTube 视频 - YouTube 教程- 时间线 19:25 左右 - 你会看到弹出到 root 只是跳回开始。

更新2:

此问题已在 iOS 16.2 中修复

Dav*_*man 6

Apple 在 iOS 16.2 上已修复此问题

\n

对于 iOS 16.0 和 16.1,这是一个 100% 有效的单行解决方案。将此 SPM 库添加到您的代码库https://github.com/davdroman/swiftui-navigation-transitions(版本 0.7.1 或更高版本),然后简单地:

\n
import NavigationTransitions\nimport SwiftUI\n\nstruct DemoPop: View {\n\n    @State private var path = NavigationPath()\n\n    var body: some View {\n        NavigationStack(path: $path) {\n            List {\n                Section("List One") {\n                    NavigationLink("Navigate to View 1", value: "View 1")\n                    NavigationLink("Navigate to View 2", value: "View 2")\n                }\n            }\n            .navigationDestination(for: String.self) { textDesc in\n\n                VStack {\n                    Text(textDesc).padding()\n                    Button("Navigate to View 3") {\n                        path.append("View 3")\n                    }.padding()\n\n                    Button("Pop to Root View") {\n                        path.removeLast(path.count)\n                    }.padding()\n                }\n            }\n            .navigationTitle("Test Pop To Root")\n        }\n        .navigationTransition(.default) // one-liner \xe2\x9c\xa8\n    }\n}\n\n\nstruct DemoPop_Previews: PreviewProvider {\n    static var previews: some View {\n        DemoPop()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n


DrM*_*uer 5

很可能是一个错误,请向 Apple 提交反馈。

也就是说,如果您使用的是 iOS,则可以使用以下 hack 来解决这个问题:

import UIKit

let animation = CATransition()
animation.isRemovedOnCompletion = true
animation.type = .moveIn
animation.subtype = .fromLeft
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)

UIApplication.shared.keyWindow!.layer.add(animation, forKey: nil)
self.navigationPath.removeLast()
Run Code Online (Sandbox Code Playgroud)