[SwiftUI]画面遷移を行う

目次

概要

Swiftではpresentメソッドやpushメソッドを使用して画面遷移ができた。
SwiftUIではそのようなメソッドは手軽に実装する場合は用意されていない。
そのため、どうすれば画面遷移ができるかメモしていく。

ソースコード

import SwiftUI

@main
struct TestApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            TransScreenView()
        }
    }
}

遷移前の画面

import Foundation

class TransScreenViewModel: ObservableObject {
    @Published var isFullScreenPresented: Bool = false
    @Published var isPresented: Bool = false
    @Published var isPushTrans: Bool = false
}
import SwiftUI

struct TransScreenView: View {
    @ObservedObject var viewModel: TransScreenViewModel = TransScreenViewModel()
    var body: some View {
        NavigationView {
            ZStack {
                VStack {
                    Spacer()
                    Button {
                        self.viewModel.isPresented = true
                    } label: {
                        Text("presentメソッドの画面遷移")
                    }
                    Spacer()
                    Button {
                        self.viewModel.isFullScreenPresented = true
                    } label: {
                        Text("presentメソッドの画面遷移FullScreen")
                    }
                    Spacer()
                    NavigationLink {
                        TransScreenSecondView(text: "pushの遷移", backgroundColor: Color.cyan)
                    } label: {
                        Text("pushメソッドの画面遷移")
                    }
                    Spacer()
                }
                .fullScreenCover(isPresented: self.$viewModel.isFullScreenPresented) {
                    TransScreenSecondView(text: "presentの遷移", backgroundColor: Color.green, isFullScreen: true)
                }
                .sheet(isPresented: self.$viewModel.isPresented) {
                    TransScreenSecondView(text: "presentの遷移", backgroundColor: Color.purple)
                }
            }
        }
    }
}

遷移後の画面

import SwiftUI

struct TransScreenSecondView: View {
    @Environment(\.dismiss) var dismiss
    
    var text: String
    var backgroundColor: Color
    var isFullScreen: Bool?
    
    init(text: String, backgroundColor: Color, isFullScreen: Bool? = nil) {
        self.text = text
        self.backgroundColor = backgroundColor
        self.isFullScreen = isFullScreen
    }
    
    var body: some View {
        ZStack {
            backgroundColor
            VStack {
                Spacer()
                Text("\(text)")
                Spacer()
                if isFullScreen ?? false {
                    Button {
                        dismiss()
                    } label: {
                        Text("元の画面に戻る")
                    }
                    Spacer()
                }
            }
        }
    }
}

デモ動画

詳細

画面遷移はこんな感じで一般的な範囲だと3パターンかなと思っている。

遷移パターン内容
sheet画面下から遷移するパターン。
遷移後は下にスワイプすることで前の画面に戻ることができる。
fullScreenCover画面下から遷移するパターン。
遷移後はボタンで前の画面に戻る形式になる。
NavigationLinkNavigationBarでタイトルを更新しながら画面遷移を行う。
遷移後は左上の戻るボタンで前の画面に戻る形式になる。

sheet

.sheet(isPresented: self.$viewModel.isPresented) {
    // 遷移先の画面
}

sheetは上記のように実装する。
特に難しいことはないと思う。

fullScreenCover

.fullScreenCover(isPresented: self.$viewModel.isFullScreenPresented) {
    // 遷移先の画面
}

sheetと同様の実装。
ただ、前の画面に戻る必要がある時は、遷移先の画面でdismissメソッドに該当するものを実装する。

@Environment(\.dismiss) var dismiss

遷移先の画面で上記のdismissを定義する。

Button {
    dismiss()
} label: {
    Text("元の画面に戻る")
}

そして、上記のように前の画面に戻りたいタイミングでdismissメソッドを呼び出す。
上記の例ではボタンにしているが、一般的ではないにしろ、時間式でも、スワイプなど、実装方法は他にもある。

NavigationLink

SwiftでいうPush遷移。swiftではpushメソッドを使用していたが、SwiftUIは以下のように実装する。

NavigationView {
    NavigationLink {
        // 遷移先の画面
    } label: {
        Text("表示したい文字列")
    }
}

ボタンを押下した時に画面遷移したいため、Buttonを使用したくなるが、NavigationLinkを使用することに注意。
また、Navigationのタイトル表示に関しては別ページ参照。
また、遷移前の画面で設定した値を遷移先の画面へ渡したい場合も別ページ参照。