SwiftUI: NavigationView/NavigationLink: launch with destinat



iOS Mail应用程序启动时,你最近查看的邮箱已经被推到导航堆栈中,尽管它实际上是一个细节屏幕,根视图控制器是所有邮箱的列表。这在UIKit中是微不足道的,因为推送到导航控制器上是微不足道的,可以在viewDidLoad或applicationDidFinishLaunching中完成。

NavigationView和NavigationLink是SwiftUI中执行导航推送/弹出的api, NavigationLink支持一些模拟程序化导航的api——但我不太清楚如何支持这个特定的用例。每次屏幕出现时都调用onAppear闭包(更像viewDidAppear而不是viewDidLoad),因此设置对应于NavigationLink的selection值将导致在用户尝试弹出时重复推送详细屏幕。我可以尝试做一些黑客围绕维护一个State屏幕是否已经被新观看,但它似乎并不理想。(我也有一些问题围绕NavigationLink的selectionAPI是脆弱的,但这可能是一个单独的问题。)

有什么建议吗?我如何启动应用程序到一个细节屏幕,但在没有任何编程干预的情况下,NavigationView正常运行?

如果你不需要在模态或动画中呈现你的视图,你应该通过使用程序化导航(带有选择绑定的NavigationLink)来获得所需的行为。

例如,如果它是你的应用程序的根目录,下面的代码应该可以工作:

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"),没有动画。

然而,有一个问题。如果你需要在工作表中显示这个视图,detail视图将会被动画推送,这可能不是你想要的。

基于这个答案,您可以在初始创建时抑制动画,但在后续导航时将其打开:

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
}
}
}

最新更新