NavigationStackの概要と使い方

この記事は約9分で読めます。

NavigationStack ビューは、SwiftUI 3.0(iOS 16、macOS 13、tvOS 16、watchOS 9から利用可能)で導入された新しいナビゲーション機能です。この機能は、従来の NavigationViewNavigationLink の組み合わせに代わるもので、SwiftUIでのナビゲーション体験をさらに強化し、管理しやすくします。

  • iOS:16.0以上
  • XCode(当サイトの環境):15.0.1

NavigationStackとは?

  1. ナビゲーション(Navigation): これはユーザーがアプリケーション内で異なるビュー間を移動するプロセスを指します。ユーザーがアプリ内で行う画面の遷移や、異なるコンテンツへのアクセスなどがこれにあたります。
  2. スタック(Stack): プログラミングにおける「スタック」とは、データ構造の一種で、要素が追加されたり削除されたりする際に「後入れ先出し(LIFO: Last In, First Out)」の原則に従うものです。スタックに要素を追加することを「プッシュ」と呼び、要素を取り出すことを「ポップ」と呼びます。

プログミングにおけるスタックは、よく以下のような図で説明されます。
スタックという器の中に1つずつ要素を追加していきます。要素の追加にあたっては上に積み上げていき、取り出す時は上から順番に取り出していくシンプルな処理方法です。

NavigationStackでは、ユーザーが新しいビューに移動する際にそのビューがスタックにプッシュされ、戻る際にはスタックからポップされるという動作をします。つまり、ユーザーのナビゲーション履歴がスタックのように管理されることを示しています。

NavigationStackの特徴

  • スタックベースのナビゲーション: ユーザーがナビゲートすると、ビューがスタックにプッシュされ、戻るときにはスタックからポップされます。
  • プログラマティックなナビゲーション: ナビゲーションはコードで制御可能で、プログラムによるビューのプッシュやポップが容易です。
  • 柔軟性: 複数のビューをスタックに積み、ユーザーがナビゲーションパスを自由に進むことができます。

基本的な使用方法

NavigationStackを使用して、ユーザーがナビゲーションを通じて異なるビューに移動できるようにします。以下は、基本的な使用例です。

import SwiftUI

struct NavigationStackSmp: View {
    var body: some View {
        NavigationStack {
            List {
                NavigationLink("詳細を表示", destination: DetailView())
                // 他のリストアイテム...
            }
        }
    }
}

struct DetailView: View {
    var body: some View {
        Text("詳細ビュー")
    }
}

この例では、リストの各アイテムをタップするとDetailViewに移動します。

メインビュー
詳細ビュー

動的なナビゲーション(動的なナビゲーション)

NavigationStackと組み合わせてnavigationDestinationを使用すると、特定のデータ型に基づいてナビゲーションの目的地(destination)を動的に決定することができます。

基本的な使い方

まず、ナビゲーションの目的地となるビューを準備します。次に、NavigationStack内でnavigationDestination(for:destination:)を使用し、特定のデータ型に基づいてどのビューへナビゲートするかを定義します。このメソッドは、データ型を受け取り、そのデータ型に対応するビューを返します。

import SwiftUI

// ナビゲーションで使用するデータ型を定義
struct NaviItem: Identifiable, Hashable {
    let id: Int
    let title: String
}

// メインビュー
struct NaviDstSmp: View {
    // ナビゲーションで使用するデータのリスト
    let items = [NaviItem(id: 1, title: "First"), NaviItem(id: 2, title: "Second")]
    
    var body: some View {
        NavigationStack {
            List(items) { item in
                NavigationLink(item.title, value: item)
            }
            // navigationDestinationを使用してナビゲーションの目的地を定義
            .navigationDestination(for: NaviItem.self) { item in
                DetailNaviView(item: item)
            }
        }
    }
}

// ナビゲーションの目的地となるビュー
struct DetailNaviView: View {
    let item: NaviItem
    
    var body: some View {
        Text("アイテムのタイトル: \(item.title)")
    }
}

この例では、Item型のデータを持つリストがあり、各アイテムをタップすると、対応するDetailViewにナビゲートします。navigationDestination(for:destination:)メソッドは、選択されたItem型のデータに基づいて、適切なDetailViewを動的に表示するために使用されています。

メインビューをnavigationDestinationを使用せず以下のように書き換えることも可能です。

struct NaviDstSmp: View {
    // ナビゲーションで使用するデータのリスト
    let items = [NaviItem(id: 1, title: "First"), NaviItem(id: 2, title: "Second")]
    
    var body: some View {
        NavigationStack {
            List(items) { item in
                NavigationLink(item.title, destination: DetailNaviView(item: item))
            }
        }
    }
}

navigationDestinationを使用するときの注意点

複数の箇所でnavigationDestinationのデータ型の指定部分に同じデータ型を指定すると、想定しない動作となることがあります。

例えば先ほどのプログラムにナビゲーションの階層を1つ増やして、詳細ビューの中でさらにNavigationLinkを使用しています。
navigationDestination(for: NaviItem.self)の引数”NaviItem”をメインビューと詳細ビューの2箇所で使用するようにしました。

意図する動作

このコードのにおいて詳細ビュー(DetailNaviView)で意図している動作は、リンクを押すとDetailNaviView2が呼び出されることです。

実際の動作

しかし実際には、DetailNaviViewが延々と呼び出される動作となります。

import SwiftUI

// ナビゲーションで使用するデータ型を定義
struct NaviItem: Identifiable, Hashable {
    let id: Int
    let title: String
}

// メインビュー
struct NaviDstSmp: View {
    // ナビゲーションで使用するデータのリスト
    let items = [NaviItem(id: 1, title: "First"), NaviItem(id: 2, title: "Second")]
    
    var body: some View {
        NavigationStack {
            List(items) { item in
                NavigationLink(item.title, value: item)
            }
            // navigationDestinationを使用してナビゲーションの目的地を定義
            .navigationDestination(for: NaviItem.self) { item in
                DetailNaviView(item: item)
            }
        }
    }
}

// ナビゲーションの目的地となるビュー
struct DetailNaviView: View {
    // ナビゲーションで使用するデータのリスト
    let items = [NaviItem(id: 1, title: "First"), NaviItem(id: 2, title: "Second")]
    let item: NaviItem
    
    var body: some View {
        Text("親ビューから渡されたタイトル: \(item.title)")
        List(items) { item in
            NavigationLink(item.title, value: item)
        }
        // navigationDestinationを使用してナビゲーションの目的地を定義
        .navigationDestination(for: NaviItem.self) { item in
            DetailNaviView2(item: item)
        }
    }
}
struct DetailNaviView2: View {
    let item: NaviItem
    
    var body: some View {
        Text("アイテムのタイトル: \(item.title)")
    }
}

まとめ

NavigationStackは、SwiftUIでのナビゲーションをより直感的で柔軟にします。
ユーザーインターフェースの流れをより細かく制御し、複雑なナビゲーションパターンを実現するのに役立ちます。

タイトルとURLをコピーしました