【SwiftUI】NavigationStackで一気にルートビューに戻る方法

この記事からわかること
- SwiftUIのNavigationStackの使い方
- 孫ビューからルートビューまで一気に戻る方法
- dismissを使用した遷移の操作
index
[open]
\ アプリをリリースしました /
Swift UIでNavigationStackを使用した画面遷移機能を実装時にルートビューまで一気に戻る方法をまとめていきます。
孫ビューからルートビューまで一気に戻る方法
孫ビューまで遷移した状態から子ビューをスキップしてルートビューまで画面を戻すにはNavigationStackの引数にパス情報を保持させる方法を取ることで実装できます。
NavigationStack(path: $path) {
}
例えば以下は「数値の増加とともに深い階層に潜り込んでいくプログラム」です。この場合、遷移するとpath
の中にはどんどん遷移履歴が格納されていきます。

struct TestNavigationView: View {
@State private var path: [Int] = []
@State var num:Int = 0
var body: some View {
NavigationStack(path: $path) {
List{
Text("\(num)")
Button {
num += 1
path.append(num)
} label: {
Text("Num Add")
}
}
.navigationDestination(for: Int.self) { num in
ChildView(path: $path,num: $num)
}
}.onChange(of: path) { _ in
print(path) // [1] → [1, 2] → ....
}
}
}
struct ChildView: View {
@Binding var path:[Int]
@Binding var num:Int
var body: some View {
List{
Text("\(num)")
Button {
num += 1
path.append(num)
} label: {
Text("Num Add")
}
Button {
num -= 1
path.removeLast()
} label: {
Text("1つ戻る")
}
Button {
num = 0
path.removeAll()
} label: {
Text("ルートビューまで一気に戻る")
}
}
.navigationTitle("ChildView")
.navigationBarBackButtonHidden(true)
}
}
ルートビューまで戻るには配列形式で管理している遷移履歴の中身をremoveAll
メソッドで空にすることで実装することができます。
パス情報を保持させない状態で実装する
先ほどの形式ではなく、以下のようなシンプルなNavigationStackを使用している場合には一気にルートビューに戻る方法は用意されていないので自前で実装する必要があります。
NavigationStack {
}
方法としてはdismiss
メソッドを戻りたい回数分実行することで実装することができます。具体的には子側から戻るためのdismiss
メソッドをクロージャーで渡し、孫側から親のメソッドを実行させます。しかしこの方法の場合は間の子ビューも一瞬表示されるような遷移になるので注意してください。例えば以下は孫ビューからルートビュー(2個上)まで戻したい場合です。
struct TestNavigationView: View {
var body: some View {
NavigationStack {
NavigationLink("ChildView", destination: ChildView())
}
}
}
struct ChildView: View {
@Environment(\.dismiss) var dismiss
var body: some View {
VStack{
Text("ChildView")
NavigationLink("GrandChildView", destination: GrandChildView(parentFunction: {dismiss()}))
}
}
}
struct GrandChildView: View {
@Environment(\.dismiss) var dismiss
var parentFunction:() -> Void
var body: some View {
VStack{
Text("GrandChildView")
Button {
dismiss()
parentFunction()
} label: {
Text("ルートビューまで戻る")
}
}
}
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。