はじめに
UdemyでswiftUIを学んでいた際に、画面遷移についての勉強しました。
Udemy上では、3種類(モーダル遷移(半分と全画面)とナビゲーション遷移)だけでしたが、Claudeに聞いたところ他にも3種類、つまり計6種類あるそうなので、それを試しにやってみました!!
画面遷移として参考にしていただけますと幸いです!!
この記事の役割
- 自分の備忘録的な立ち位置
- 引き出し
- こういう画面遷移したい→このコードブロックだ!!みたいな辞書・当て感
画面遷移
モーダル遷移
下から上にスライドで画面が出てくるやつ。
IT分野では他の操作を一時停止させ画面上にポップアップ表示する「モーダルウィンドウ」と言う(へぇ〜)。
コードでは、遷移した後に、閉じるボタンを押下することで元の画面に戻る機能も追加している。
種類
- sheet
- 上型に隙間ができる
- スワイプで閉じることができる
- 表示を半分など様々ある
- fullScreenCover
- 画面全体に表示される
ポイント
<更新していいように$マークをつける>
SwiftUIでは、画面に表示する値が変わると、画面が自動で更新される仕組みがあります。
その「変化を監視してくれる箱」が @State です。
@State で宣言した変数には、2通りのアクセス方法があります。
-
isShowingView→ 値を 読む だけ -
$isShowingView→ 値を 読み書き できる ・・・⭐️ この$マークが大切
掲示板に例えると、isShowingView は掲示板を「見るだけ」、
$isShowingView は掲示板に「書き込めるマジックペンを渡す」イメージです。
挙動
AViewにある「BViewへの遷移」ボタンを押下すると、真っ黄色のBViewへ遷移するコードです。

コード
//
// AView.swift
// Part10_ScreenTransition
//
// Created by なみふみ on 2026/03/17.
//
import SwiftUI
// HOME 画面のAViewを作成
struct AView: View {
@State var isShowingBView = false // BViewを表示しているかどうか?の判定。ボタン押下によってtrueになる
@State var isShowingFullScreen = false // 全画面用
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
// 画面遷移ボタンの処理
// 半分モーダル
Button("BViewへモーダル遷移 半分") {
isShowingBView = true
}
.sheet(isPresented: $isShowingBView) { // $マークを忘れない!!
BView()
.presentationDetents([.medium]) // 他にもmediumなどがある
}
// 全画面表示
Button("BViewへモーダル遷移 全画面") {
isShowingFullScreen = true
}
.fullScreenCover(isPresented: $isShowingFullScreen) {
BView()
}
}
}
}
// 遷移先の BView を作成
struct BView: View {
@Environment(\.dismiss) var dismiss // モーダル遷移を閉じるため
var body: some View {
ZStack {
VStack {
Text("BView")
Button("閉じる") {
dismiss()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.yellow)
.ignoresSafeArea() // 上側も色を塗る
}
}
}
#Preview {
AView()
}
ナビゲーション遷移
横に遷移するver
ポイント
ナビゲーション遷移は、親子関係で継承される。
つまり、子のUIのときに、わざわざナビゲーション遷移を設定しなくても良い!!(便利〜)
挙動
AView(Home画面) > CView > DViewへ遷移します。
コード
//
// AView.swift
// Part10_2_ScreenTransition
//
// Created by なみふみ on 2026/03/17.
//
import SwiftUI
struct AView: View {
var body: some View {
NavigationStack{ // 一番親画面につける
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
// CViewへナビゲーション遷移をする
// 戻る
NavigationLink("CViewへバビゲーション遷移") {
CView()
}
}.navigationTitle("AView") // これはiphone画面の上に出てくるタイトル。
}
}
}
struct CView: View {
var body: some View {
// ナビゲーション遷移は、親から継承されるため、改めて設定する必要はない!!
VStack {
Text("CView")
NavigationLink("DViewへバビゲーション遷移") {
DView()
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.green)
.ignoresSafeArea()
.navigationTitle("CView")
}
}
struct DView: View {
var body: some View {
ZStack {
Text("DView")
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.blue)
.ignoresSafeArea()
.navigationTitle("DView")
}
}
#Preview {
AView()
}
タブ切り替え
ポイント
- TabViewの中に、tabItemオブジェクトを入れる
挙動
コード
//
// ContentView.swift
// ScreenTransition_Tab
//
// Created by nami_fumi on 2026/03/20.
//
import SwiftUI
struct ContentView: View {
var body: some View {
// タブ遷移
TabView {
BookShelfView()
.tabItem {
Image(systemName: "book.pages")
Text("本棚")
}
ScanView()
.tabItem {
Image(systemName: "barcode.viewfinder")
Text("スキャン")
}
SettingView()
.tabItem {
Image(systemName: "gearshape.fill")
Text("設定")
}
}
}
}
// 各画面
struct BookShelfView: View {
var body: some View {
Text("本棚画面")
.font(.title)
}
}
struct ScanView: View {
var body: some View {
Text("スキャン画面")
.font(.title)
}
}
struct SettingView: View {
var body: some View {
Text("設定画面")
.font(.title)
}
}
#Preview {
ContentView()
}
(iPad向け)吹き出しで表示
ポイント
- presentationCompactAdaptation(.popover)をつけない・つけるによって、挙動が変わる
- つけない
- iPad:吹き出し
- iPhone:sheet。モーダル遷移
- つける
- iPad:吹き出し
- iPhone:吹き出し
- つけない
挙動
つけない
つける
<iPad>
つけない時と同じ
コード
//
// ContentView.swift
// ScreenTransition_Hukidashi
//
// Created by nami fumi on 2026/03/20.
//
import SwiftUI
struct ContentView: View {
@State var isShowingPopper = false
var body: some View {
VStack {
Text("本の詳細画面")
.font(.title)
// このボタンを押下
Button("詳細情報をみる") {
isShowingPopper = true
}
.buttonStyle(.borderedProminent)
.popover(isPresented: $isShowingPopper) {
// popoverの中身
// iPhone > sheetになる
// iPad >
VStack {
Text("本の詳細情報")
.font(.headline)
Text("著者:nami fumi")
Text("出版社:Swift出版")
Text("発売日:2026年3月")
Text("ページ数:300ページ")
}
.padding()
.presentationCompactAdaptation(.popover) // この部分でiPhoneでも吹き出しになる
}
}
}
}
#Preview {
ContentView()
}
ダイアログ表示
ポイント
- アラートの場合
- roleが大切
- role: .destructive
- 赤色:削除・危険な操作
- role: .cancel
- 太字:キャンセル操作
- role: .destructive
- roleが大切
挙動
コード
<基本>
//
// Alert.swift
// ScreenTransition_Dailog
//
// Created by nami fumi on 2026/03/20.
//
import SwiftUI
struct Alert: View {
@State var isShowingAlert = false
var body: some View {
VStack(spacing: 24) {
// シンプルなアラート
// ボタンの設定
Button("お知らせの表示") {
isShowingAlert = true
}
.buttonStyle(.borderedProminent)
// ボタンの設定
// アラートの設定
.alert("お知らせ", isPresented: $isShowingAlert) {
Button("ok") {}
} message: {
Text("新しい本が追加されました!")
}
// アラートの設定
}
}
}
#Preview {
Alert()
}
<キャンセル アラート>
//
// Alert2.swift
// ScreenTransition_Dailog
//
// Created by nami fumi on 2026/03/20.
// キャンセルあり > ポイントはrole
import SwiftUI
struct Alert2: View {
@State var isShowingDeleteAlert = false
var body: some View {
Button("本を削除する") {
isShowingDeleteAlert = true
}
.buttonStyle(.borderedProminent)
.tint(.red) // ボタンの背景を赤色にする
.alert("削除の確認", isPresented: $isShowingDeleteAlert) {
Button("⭐️削除⭐️", role: .destructive) {
print("削除しました")
}
Button("キャンセル", role: .cancel) {}
} message: {
Text("この本を削除しますか?\nこの操作は取り消せません")
}
}
}
#Preview {
Alert2()
}
参考文献
- Udemy モーダル遷移
- Udemy ナビゲーション遷移
- claude






