SwiftUI:NavigationDestinationLink已弃用

6
今天早上安装了 Xcode 11 beta 5 后,我注意到 NavigationDestinationLink 被废弃了,建议使用 NavigationLink
以下是苹果在发布说明中针对此问题的声明:

NavigationDestinationLink 和 DynamicNavigationDestinationLink 已弃用;它们的功能现已包含在 NavigationLink 中。 (50630794)

我使用 NavigationDestinationLink 的方式是通过 self.link.presented?.value = true 编程推入新视图堆栈。这个功能似乎在 NavigationLink 中没有了。
大家有什么想法吗? 我不希望再使用 NavigationDestinationLink,因为它已被废弃...
谢谢!
更新: 实际上,NavigationDestinationLink 的方法不再有效,所以我想我们无法再进行编程推入了?
更新2:
NavigationLink(destination: CustomView(), isActive: $isActive) {
    return Text("")
}

这个代码可以运行,但是当你将isActive设置为true时,任何状态更新都会触发这段代码并且不断地推送。另外,如果你将它设置回false,它会弹出视图。 不仅如此,如果你将isActive设置为true,它会推送视图(好的),如果我们按返回按钮,它会返回然后立即再次推送,因为它仍然是真的。 尝试使用onAppear,但是当返回到它时,它不会被调用... 我不确定我们应该如何使用它。

1
NavigationLink(destination: Your view())?这不应该可以工作吗? - LearningPhase
我也对此很感兴趣。我无法在任何地方找到替代品。 - Thomas Vos
5个回答

21

花了一些时间接触 NavigationLink(destination:isActive) 后,我比以前的 NavigationDestinationLink 更喜欢它。旧视图有些令人困惑,而这种新方法似乎更加优雅。并且一旦我知道如何在没有动画的情况下推送视图,应用程序启动时的状态恢复将变得非常容易。

但是有一个问题,一个很大又很丑的 bug. :-(

enter image description here

通过编程方式推送视图很好用,同样可以通过编程方式弹出它。问题是当我们在推送的视图中使用 BACK 按钮时,其行为每隔一次都会发生异常。第一次弹出视图时,视图会立即弹出并再次推送。第二次就能正常工作。然后第三次又开始了。

我创建了一个错误报告 (编号在此处)。我建议您也这样做,并引用我的编号,以帮助 Apple 将它们组合在一起并更多地关注这个问题。

我设计了一个解决方法,基本上是用我们自己的按钮替换默认的返回按钮:

class Model: ObservableObject {
    @Published var pushed = false
}

struct ContentView: View {
    @EnvironmentObject var model: Model

    var body: some View {
        NavigationView {
            VStack {
                Button("Push") {
                    // view pushed programmatically
                    self.model.pushed = true
                }

                NavigationLink(destination: DetailView(), isActive: $model.pushed) { EmptyView() }
            }
        }
    }
}

struct DetailView: View {
    @EnvironmentObject var model: Model

    var body: some View {
        Button("Bring me Back (programatically)") {
            // view popped programmatically
            self.model.pushed = false
        }
        // workaround
        .navigationBarBackButtonHidden(true) // not needed, but just in case
        .navigationBarItems(leading: MyBackButton(label: "Back!") {
            self.model.pushed = false
        })
    }
}

struct MyBackButton: View {
    let label: String
    let closure: () -> ()

    var body: some View {
        Button(action: { self.closure() }) {
            HStack {
                Image(systemName: "chevron.left")
                Text(label)
            }
        }
    }
}

是的,看起来我刚刚在我的“更新2”中写了关于那个的内容 :( - Benjamin Clanet
这真的很有趣,谢谢分享。然而,它仍然有不同的行为。以前 DetailView 只会被创建一次。现在每次 ContentView 更新时都会创建它。这对我造成了一些问题,因为详细视图的状态会重置。我关于我的问题创建了一个新的问题。我真的很感激你的帮助。https://dev59.com/GbXna4cB1Zd3GeqPKm7Q - Thomas Vos
注意:EmptyView() 仍然占用空间。这可以通过按钮在中心线上方可见。我觉得这相当烦人。 - philipp
1
@philipp 空间被 NavigationLink 占用,而不是 EmptyView。无论如何,您始终可以添加 NavigationLink(...) {..}.frame(width: 0, height: 0) - kontiki
@kontiki 很好的想法。我正在努力从UIKit集合视图内部加载新的导航视图,那个技巧和使用 NavigationLink(tag)应该可以解决问题。 - philipp

3
为了改进解决方法而不用替换后退按钮,你可以使用上述代码。
NavigationLink(destination: Test().onAppear(perform: {
    self.editPushed = nil
}), tag: 1, selection: self.$editPushed) {
    Button(action: {
        self.editPushed = 1
    }) {
        Image(systemName: "plus.app.fill")
            .font(.title)
    }
}

onAppear块将擦除选择值,以防止显示详细视图两次


这个确实有效,但好像不允许我从详细视图编程方式返回主视图。 - Fabian Streitel
我发现将当前视图从导航堆栈中弹出的方法就像这里描述的那样有效:https://dev59.com/N1MI5IYBdhLWcg3wS5gv#57594164 - Fabian Streitel

1

您还可以使用NavigationLink(destination:tag:selection)。

NavigationLink(destination: MyModal(), tag: 1, selection: $tag) {
    EmptyView()
}

通过编程的方式,您可以将标签设置为1,以推动MyModal。这种方法与使用Bool绑定变量的方法具有相同的行为,因此第一次弹出时会立即推送视图,希望他们在下一个测试版中修复它。

我唯一看到这种方法的缺点是,与DynamicNavigationDestinationLink相比,即使您不需要一个视图,也需要向NavigationLink提供一个视图。希望他们能找到一种更清晰的方法来允许我们以编程方式推送。


0

所选答案中使用的方法已经被弃用了。这里是从这个答案在这个帖子中复制的解决方案。

    @State private var readyToNavigate : Bool = false

    var body: some View {
        NavigationStack {
           VStack {
              Button {
                  //Code here before changing the bool value
                  readyToNavigate = true
              } label: {
                  Text("Navigate Button")
              }
          }
           .navigationTitle("Navigation")
           .navigationDestination(isPresented: $readyToNavigate) {
              MyTargetView()
          }
       }
   }


这对我应该是有效的,没有编译错误,NavStack嵌入在tabBar中,但没有转换。 - Marlhex

0

解决方案是为您的详细视图创建自定义返回按钮,并手动弹出详细视图。

.navigationBarItems(leading:
                Button(action: {
                    self.showDetail = false
                }) {
                    Image(systemName: "chevron.left").foregroundColor(.red)
                        .font(.system(size: 24, weight: .semibold))
                    Text("Back").foregroundColor(.red)
                    .font(.system(size: 19))
                }
            )

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