Posted at

[SwiftUI] NavigationLinkの遷移先を動的に変更する

https://qiita.com/noppefoxwolf/items/c10c50cbefb7896107fd

で解説したように、型消去を利用することで遷移先の画面を事前に指定することなく動的に与えることが出来ます。

今回はNavigationLinkでも同様のことが出来たので解説します。

一点、NavigationLinkはButtonの機能も有しているため扱いが多少異なります。

このエントリでは、以下のようにEmptyViewを入れることでNavigationLinkをほぼ純粋な画面遷移のObserverとして利用しています。

NavigationLink(destination: destination, tag: tag, selection: $selection) {

EmptyView()
}

NavigationLinkはsheetと違い、identifarableによって遷移先を変更する機能は無いのですが遷移事態を要求することが出来るイニシャライザが存在します。


public init<V>(destination: Destination, tag: V, selection: Binding<V?>, @ViewBuilder label: () -> Label) where V : Hashable

tagで指定した値がselectionに流れることで、destinationをpushするような挙動になります。

これを利用して、selection代入時に型消去したdestinationを更新することで一つのNavigationLinkを複数の箇所やボタン以外から制御できるようになります。

struct ContentView: View {

private let defaultTag: Int = 8888
@State var destination: AnyView? = nil
@State var tag: Int? = nil

var body: some View {
NavigationView {
VStack {
Button(action: {
self.destination = AnyView(Text("child 1"))
self.tag = self.defaultTag
}) {
Text("tap 1")
}
Button(action: {
self.destination = AnyView(Text("child 2"))
self.tag = self.defaultTag
}) {
Text("tap 2")
}
NavigationLink(destination: destination, tag: defaultTag, selection: $tag) {
EmptyView()
}
}
}
}
}

原理としては、tagがbindingされているので同じクラスでdestinationを定義すれば、更新時にbodyが呼ばれてNavigationLinkの遷移先が入った状態で遷移するイメージです。