SwiftUI NavigationStackの使い方【実用編】

ここではNavigationStackについて少し詳細にリストの表示から複数のページへ遷移する方法などを紹介していきたいと思います。

基本的な使用方法について知りたいって人は以下のページで紹介していますのでそちらを参考にしてみてください。

SwiftUI NavigationStackの使い方【初心者向け解説】

目次CLOSE 1. 1. NavigationStackの基本構造 2. 2. 複数画面を管理する 3. 3. パスを使った画面遷移管理 4. まとめ SwiftUIのiOS16以降で導入されたNavigationStackは、従…

SwiftUIのiOS16以降で導入されたNavigationStackは、従来のNavigationViewの後継となる新しいナビゲーションコンポーネントです。従来よりも柔軟で管理しやすくなっています。

主な違いとしてNavigationStackが遷移状態を配列で管理でき、データ駆動型のナビゲーションやディープリンクに対応しやすくなった点が挙げられます。ボタンタップで子画面表示

ボタンタップで子画面表示(遷移状態管理にNavigationPathを使用)

Case1 ボタンタップで子画面表示

遷移状態の管理にNavigationPathを使用しButtonタップでNavigationPathの配列にappendでInt値を設定することで.navigationDestinationで定義した画面へ遷移します。

/// ボタンタップで子画面表示
/// NavigationPathを使用しpathに値設定で.navigationDestination で子画面表示
struct NavigationStackSample_Case1_1: View {
    @State var path = NavigationPath()
    var body: some View {
        NavigationStack(path: $path) {
            Button("遷移") {
              //   タップでpathにInt0を設定
              path.append(1)
            }
            //  ナビゲーション修飾子
            .navigationTitle("ホーム")
            .navigationBarTitleDisplayMode(.inline)
            // pathにIntがappendされた時に遷移するView
            .navigationDestination(for: Int.self, destination: { value in
                Text("子画面(\(value))")
            })
        }
    }
}

ポイント: pass に Intの値 をappendすることによりnavigationDestinationで定義した子画面へ遷移します。

ボタンタップで子画面表示(遷移状態管理にInt型配列を使用)

Case2 ボタンタップで子画面表示


遷移状態の管理にInt型の配列を使用しIntに値設定で.navigationDestinationで子画面表示

NavigationPathを使用しButtonタップでNavigationPathの配列にappendでInt値を設定することで.navigationDestinationで定義した画面へ遷移します。


/// ボタンタップで子画面表示
/// Int配列を使用しIntに値設定で.navigationDestinationで子画面表示
/// 遷移先への引数型が1パターンの場合はNavigationPathではなく
/// 使用する引数の型でも遷移できる
struct NavigationStackSample_Case1_2: View {
    @State var transition: [Int] = []
    var body: some View {
        NavigationStack(path: $transition) {
            Button("遷移") {
              //   タップでpathにInt0を設定
              transition.append(1)
            }
            //  ナビゲーション修飾子
            .navigationTitle("ホーム")
            .navigationBarTitleDisplayMode(.inline)
            // pathにIntがappendされた時に遷移するView
            .navigationDestination(for: Int.self, destination: { value in
                Text("子画面(\(value))")
            })
        }
    }
}

ポイント: 遷移先への引数型が1パターンの場合はNavigationPathではなく使用する引数の型(上の例ではInt型を使用)でも遷移できる

リストタップで子画面表示

Case3 リストボタンタップで子画面表示


遷移状態の管理にInt型の配列を使用しIntに値設定で.navigationDestinationで子画面表示

NavigationPathを使用しButtonタップでNavigationPathの配列にappendでInt値を設定することで.navigationDestinationで定義した画面へ遷移します。

/// リストタップで子画面表示
/// pathに値設定で.navigationDestinationで子画面表示
struct NavigationStackSample_Case2: View {
    @State var path = NavigationPath()
    var body: some View {
        //  pathによる遷移を行うNavigationStack
        NavigationStack(path: $path) {
            List {
              Button("遷移 ページ1") {
                path.append(1)
              }
              Button("遷移 ページ2") {
                path.append(2)
              }
              Button("遷移 ページ3") {
                path.append(3)
              }
            }
            //  ナビゲーション修飾子
            .navigationTitle("ホーム")
            .navigationBarTitleDisplayMode(.inline)
            .navigationDestination(for: Int.self, destination: { appended in
              Text("ページ:\(appended)")
            })
        }
    }
}

リストタップで子画面表示 NavigationLink を使用

Case4 NavigationLink によりリストボタンを設定し、タップで子画面(クロージャ)へ遷移します。

/// リストタップで子画面表示
/// NavigationLink による子画面(クロージャ)表示
struct NavigationStackSample_Case3: View {
  var body: some View {
    NavigationStack {
      List {
        NavigationLink("子画面へ遷移") {
            Text("子画面")
          }
      }
      //  ナビゲーション修飾子
      .navigationTitle("ホーム")

    }
  }
}

ポイント:.navigationDestinationではなくNavigationLinkを使用しての小画面へ遷移します。

リストタップで子画面表示 pathに値設定で型別に定義した.navigationDestinationで子画面表示

遷移状態の管理にNavigationPathを使用し.navigationDestinationで入力型別に画面を定義し、ButtonタップでNavigationPathの配列に表示させたい画面の入力型をappendすることで指定した画面へ遷移します。

/// リストタップで子画面表示
/// pathに値設定で型別に定義した.navigationDestinationで子画面表示
struct NavigationStackSample_Case4: View {
    @State var path = NavigationPath()
    var body: some View {
        //  pathによる遷移を行うNavigationStack
        NavigationStack(path: $path) {
            List {
              Button("遷移 ページ1") {
                path.append(1)
              }
              Button("遷移 ページ2") {
                path.append(2)
              }
              Button("遷移 ページ3") {
                path.append(3)
              }
              Button("遷移 ページ4") {
                path.append("文字")
              }
            }
            //  ナビゲーション修飾子
            .navigationTitle("ホーム")
            .navigationBarTitleDisplayMode(.inline)
            .navigationDestination(for: Int.self, destination: { appended in
              Text("ページ:\(appended)")
            })
            .navigationDestination(for: String.self, destination: { appended in
              Text("文字列ページ:\(appended)")
            })
        }
    }
}

複数ページ&複数階層の画面遷移

応用として、画面に階層化し各階層への遷移を管理を少ないコードで実装することができる

Home画面にリストボタンでページA〜ページEへの遷移ボタンを準備し以下のように階層遷移を構成する。

ページAはページBへ遷移可能

ページBはページCへ遷移可能

ページCはページDへ遷移可能

ページDはページEへ遷移可能

ページEは戻るだけ可

  • ページAはページBへ遷移可能
  • ページBはページCへ遷移可能
  • ページCはページDへ遷移可能
  • ページEは戻るだけ可可能
  • ページAはページBへ遷移可能


遷移イメージ


/// 複数階層の画面遷移
///
///
enum PageName {
  case pageA, pageB, pageC, pageD, pageE
}

struct NavigationStackSample_Case5: View {
    @State var path = NavigationPath()
    var body: some View {
        //  pathによる遷移を行うNavigationStack
        NavigationStack(path: $path) {
            List {
              Button("遷移 ページA") {
                path.append(PageName.pageA)
              }
              Button("遷移 ページB") {
                path.append(PageName.pageB)
              }
              Button("遷移 ページC") {
                path.append(PageName.pageC)
              }
              Button("遷移 ページD") {
                path.append(PageName.pageD)
              }
              Button("遷移 ページE") {
                path.append(PageName.pageE)
              }

            }
            //  ナビゲーション修飾子
            .navigationTitle("ホーム")
            .navigationBarTitleDisplayMode(.inline)
            .navigationDestination(for: PageName.self, destination: { value in
              switch value {
                case .pageA :
                  PageAView(path: $path)
                  //  ナビゲーション修飾子 ページタイトル設定
                  .navigationTitle("ページA")
                case .pageB:
                  PageBView(path: $path)
                  //  ナビゲーション修飾子 ページタイトル設定
                  .navigationTitle("ページB")
                case .pageC:
                  PageCView(path: $path)
                  //  ナビゲーション修飾子 ページタイトル設定
                  .navigationTitle("ページC")
              case .pageD:
                  PageDView(path: $path)
                  //  ナビゲーション修飾子 ページタイトル設定
                  .navigationTitle("ページD")
                case .pageE:
                  PageEView(path: $path)
                  //  ナビゲーション修飾子 ページタイトル設定
                  .navigationTitle("ページE")
              }
            })
        }
    }
}


struct PageAView: View {
  @Binding var path: NavigationPath
  var body: some View {
    List {
      Button("B画面へ遷移") {
        path.append(PageName.pageB)
      }
    }
  }
}

struct PageBView: View {
  @Binding var path: NavigationPath
  var body: some View {
    List {
      Button("C画面へ遷移") {
        path.append(PageName.pageC)
      }
    }
  }
}

struct PageCView: View {
  @Binding var path: NavigationPath
  var body: some View {
    List {
      Button("D画面へ遷移") {
        path.append(PageName.pageD)
      }
    }
  }
}

struct PageDView: View {
  @Binding var path: NavigationPath
  var body: some View {
    List {
      Button("E画面へ遷移") {
        path.append(PageName.pageE)
      }
    }
  }
}

struct PageEView: View {
  @Binding var path: NavigationPath
  var body: some View {
    List {
      Button("終了") {
        path.removeLast()

      }
    }
  }
}

まとめ

NavigationStackは、従来のNavigationViewよりも直感的に画面遷移を管理できるのが特徴です。画面遷移ロジックを容易に実装できます。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA