SwiftUI:NavigationView/NavigationLink:启动并推送目的地?

Posted

技术标签:

【中文标题】SwiftUI:NavigationView/NavigationLink:启动并推送目的地?【英文标题】:SwiftUI: NavigationView/NavigationLink: launch with destination pushed? 【发布时间】:2021-05-29 09:16:05 【问题描述】:

ios Mail 应用启动时,您最近查看的邮箱已被推送到导航堆栈,即使它实际上是一个详细信息屏幕,并且根视图控制器是所有邮箱的列表。这在 UIKit 中是微不足道的,因为推送到导航控制器是微不足道的,并且可以在 viewDidLoad 或 applicationDidFinishLaunching 内部完成。

NavigationView 和 NavigationLink 是用于在 SwiftUI 中执行导航推送/弹出的 API,NavigationLink 支持几个模仿编程导航的 API - 但我不太清楚如何支持这个特定的用例。每次屏幕出现时都会调用onAppear 闭包(更像viewDidAppear 而不是viewDidLoad),因此设置与 NavigationLink 对应的 selection 值将导致在用户尝试弹出时重复推送该详细信息屏幕。我可以尝试对维护State 进行一些修改,以了解屏幕是否已被新查看,但这似乎并不理想。 (关于 NavigationLink 的 selection API 不稳定,我也遇到了一些问题,但这可能是一个单独的问题。)

有什么建议吗?如何在详细信息屏幕上启动应用程序,但在没有任何程序干预的情况下让 NavigationView 正常运行?

【问题讨论】:

【参考方案1】:

如果您不需要以模式或动画的形式呈现您的视图,您应该使用编程导航(NavigationLink with selection binding)来获得所需的行为。

例如,如果它是您的应用程序的根目录,则以下内容应该有效:

struct Item: Identifiable 
    let id: Int
    let name: String


struct NormalNav: View 
    @State var items: [Item] = [
        .init(id: 0, name: "One"),
        .init(id: 1, name: "Two"),
        .init(id: 2, name: "Three")
    ]

    @State private var selection: Int? = 1

    var body: some View 
        NavigationView 
            List 
                ForEach(items)  item in
                    NavigationLink(item.name,
                                   destination: Text(item.name),
                                   tag: item.id,
                                   selection: $selection)
                
            
        
    

上面的视图应该直接打开到第二个项目(“Two”),没有动画。

但是,有一个皱纹。如果您需要在 Sheet 中显示此视图,则会使用动画推送详细视图,这可能不是您想要的。

在this answer 的基础上,您可以在初始创建时抑制动画,但在后续导航时将其重新打开:

struct ContentView: View 
    @State var items: [Item] = [
        .init(id: 0, name: "One"),
        .init(id: 1, name: "Two"),
        .init(id: 2, name: "Three")
    ]

    @State private var selection: Int? = nil
    @State var isAnimationDisabled = true
    @State var isListPresented = false

    var body: some View 
        Button("Show list") 
            isListPresented = true
        .sheet(isPresented: $isListPresented) 
            NavigationView 
                List 
                    ForEach(items)  item in
                        NavigationLink(item.name,
                                       destination: Text(item.name),
                                       tag: item.id,
                                       selection: $selection)
                    
                .animations(disabled: isAnimationDisabled)
            .onChange(of: selection)  value in
                if value == nil 
                    isAnimationDisabled = false
                
            .onAppear 
                selection = 1
            
        
    


extension View 
    func animations(disabled: Bool) -> some View 
        transaction  (tx: inout Transaction) in
            guard disabled else 
                return
            
            tx.disablesAnimations = true
            tx.animation = .none
        
    

【讨论】:

谢谢 - 我在你给我的第一个例子中使用了同样的方法(使用标签和选择的 NavigationLink)并且遇到了问题,但我会再看看我自己的代码现在我有一个工作简化的例子。

以上是关于SwiftUI:NavigationView/NavigationLink:启动并推送目的地?的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI 学习曲线

SwiftUI NavigationLink 如何到达另一个 SwiftUI 页面?

SwiftUI - 如何在 SwiftUI 中弹出到特定视图?

SwiftUI3.0将UIKit ViewController转化成 swiftUI的view

SwiftUI 五

SwiftUI/UIKit 如何将 SwiftUI 字体转换为 UIKit UIFont?