【Swift UI】NavigationStackの使い方!iOS16以降の画面遷移方法
この記事からわかること
- SwiftUIのNavigationStackとは?
- iOS16以降で画面遷移させる方法
- ナビゲーションバーのカスタマイズするには?
- NavigationSplitViewとは?
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
参考文献:Migrating to new navigation types
これまで使用していたNavigationView
構造体はiOS13.0〜16.0はDeprecated(非推奨)になったのでその代わりにNavigationStack
とNavigationSplitView
の2つの構造体への置き換えが推奨されているので今回はNavigationStack
の使い方をまとめておきたいと思います。
NavigationStack構造体
@MainActor struct NavigationStack<Data, Root> where Root : View
NavigationStack
は、非推奨となったNavigationViewの代わりに用意されたスタック(積み重ねる)構造で管理された画面遷移を実装できる構造体です。スタック構造の遷移情報は基本的に後入れ先出し(LIFO: Last In First Out; FILO: First In Last Out)で操作されます。大元となるルートビューを起源にビューを上に追加したり、ビューを削除することでViewの遷移を実装しています。
基本的な使い方はNavigationView
と変わらず、NavigationStack
でビューを囲むことで中にあるビューを管理対象にすることができます。色々変化している部分も多いので使用方法をまとめておきます。
NavigationStack {
// View
}
特にnavigationViewStyle(.stack)
の使用はNavigationStack
への移行が推奨されています。
NavigationView {
/* content */
}
.navigationViewStyle(.stack)
画面遷移の方法
これまで通り画面遷移にはNavigationStack
内でNavigationLink
構造体を使用します。使用方法は変わらないので遷移先のビューとラベルを表示することでリンクボタンを実装することができます。非推奨になっているイニシャライザもあるので注意してください。
おすすめ記事:【Swift UI】NavigationLinkの使い方!navigationDestinationとの組み合わせ
NavigationStack {
NavigationLink {
// 遷移先のビューを指定
MyNextView()
} label: {
// リンクボタンのテキストを指定
Label("MyNextViewへ", systemImage: "arrowshape.turn.up.right.fill")
}
}
また遷移情報は上記の場合、可視化できていませんが、init(path:root:)
を使用することで遷移情報を可視化し、管理、操作しやすくすることも可能です。
Navigationをカスタマイズするモディファイア
NavigationView
の時にNavigationをカスタマイズするために使用していたnavigationTitle
などのモディファイアはView
を拡張して定義されているので変わらず呼び出して使用することができます。
extension View {
public func navigationTitle(_ title: Text) -> some View
}
Navigationをカスタマイズするモディファイアを役割ごとにまとめていきます。
タイトルを付与する
ナビゲーションバーにタイトルを付与するにはnavigationTitle
モディファイアを使用します。
NavigationStack {
List {
Text("要素1")
Text("要素2")
NavigationLink("リンク1") {
MyNextView()
}
}.navigationTitle("タイトル")
}
またタイトルを付与したことで遷移後の画面の「Back」ボタンもタイトル名のボタンへと変更されます。
ナビゲーションバー(タイトル)を非表示にする
タイトルを非表示にするにはnavigationBarHidden
モディファイアを使います。
NavigationStack {
List {
Text("要素1")
Text("要素2")
NavigationLink("リンク1") {
MyNextView()
}
}.navigationTitle("タイトル")
.navigationBarHidden(true)
}
toolbar(_:for:)で非表示にする
navigationBarHidden
モディファイアはiOS16以降非推奨になったのでナビゲーションバーを非表示するにはtoolbar(_:for:)
モディファイアを使用します。
.toolbar(.hidden, for: .navigationBar)
「Back」ボタンを非表示にする
ナビゲーションバーにデフォルトで表示される「Back」ボタンを表示させたくない場合は子View側にnavigationBarBackButtonHidden
モディファイアを使えば非表示にすることができます。
struct MyNextView: View {
var body: some View {
Text("MyNextView")
.navigationTitle("MyNextView")
.navigationBarBackButtonHidden(true)
}
}
画面遷移のタイミングを変数の値とリンクさせる
navigationDestination
モディファイアを使用することで画面遷移のタイミングを変数の値が変化した時に実行することができます。
struct TestNavigationView: View {
@State var isPresented:Bool = false
var body: some View {
NavigationStack {
Button {
isPresented = true
} label: {
Text("MyNextView")
}.navigationDestination(isPresented: $isPresented) {
MyNextView()
}
}
}
}
NavigationSplitView構造体
公式リファレンス:NavigationSplitView構造体
struct NavigationSplitView<Sidebar, Content, Detail> where Sidebar : View, Content : View, Detail : View
ちなみにNavigationSplitView
はiPadなどの大画面のデバイスで使用される、2つのViewを並べた画面を実現するための構造体です。例えば以下のように使用してiPadアプリで分割したビューを構築することができます。
import SwiftUI
struct TestNavigationView: View {
let users: [User] = [
User(name: "Ame", greeting: "こんにちは"),
User(name: "Kasa", greeting: "Hello"),
User(name: "Mahiro", greeting: "コンニチハ")
]
@State private var selectedUser: User?
var body: some View {
NavigationSplitView {
MasterView(users: users, selectedUser: $selectedUser)
} detail: {
DetailView(user: selectedUser)
}
}
}
struct MasterView: View {
let users:[User]
@Binding var selectedUser: User?
var body: some View {
List(users) { user in
Button(action: { selectedUser = user }) {
Text(user.name)
}
}
.navigationTitle("Users")
}
}
struct DetailView: View {
let user: User?
var body: some View {
if let user = user {
Text(user.greeting)
.navigationTitle(user.name)
} else {
Text("No item selected")
.navigationTitle("Details")
}
}
}
struct User: Identifiable {
let id = UUID()
let name: String
let greeting:String
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。