【SwiftUI】ログイン画面⇔ログイン済画面の画面遷移
よくある、ログイン画面⇔ログイン済画面の画面遷移を、SwiftUIだけでどう実現するのか。というお話をサンプル付きで解説します。
※この記事ではSwift言語の基本的な知識を前提にしています。コード内のキーワードや書式などの不明点は参考書などを参照してください。
環境
解説は以下の環境で行います。
・Xcode
Version 11.3.1 (11C504)
・Swift
Swift version 5.1.3
・Simulator
iOS 13.2
はじめに
ログイン後の画面ではTabViewを使いたいんだけど、ログインする画面ではTabメニューを触らせたくないからTabViewは使いたくないってケースは良くありますよね。
今回はそんなケースを解説していきます。
今回使用する画面は大きく2グループあります。
〇ログインするためのグループ(TabVIewなし)
・新規登録かログインを選択できる画面
・新規登録画面
・ログイン画面
〇ログイン後のグループ(TabViewあり)
・HOME画面
・ログアウト画面
やってみる
1. ログインするための画面作成
まずはログインするための画面を作成していきます。
1-1.新規登録画面
まずは、新規登録画面を作ります。
ファイル名:SignUpVIew.swift
とりあえず画面遷移だけなので、今回はフォームとかは設置しませんが、本当の新規登録画面では、ちゃんとフォーム等を設置してください。
import SwiftUI
struct SignUpView: View {
@State private var pushSignUp = false
var body: some View {
// HomeViewへ遷移する
VStack(spacing: 80) {
Button(action: {
// ログイン時の処理を書く
// ユーザーデフォルトにtokenを保持するとか
UserDefaults.standard.set("token", forKey: "apiToken")
self.pushSignUp = true
}) {
Text("新規登録する")
}
NavigationLink(destination: ContentView(),
isActive: self.$pushSignUp) {
EmptyView()
}.hidden()
}
}
}
struct SignUpView_Previews: PreviewProvider {
static var previews: some View {
SignUpView()
}
}
この時点では、HomeViewをまだ作成していないので、エラーになりますが、構わず進めます。(全ての画面が揃うまでエラーが出続けます)
1-2.ログイン画面
まずはログイン画面を作ります。
ファイル名:SignInView.swift
import SwiftUI
struct SignInView: View {
@State private var pushSignIn = false
var body: some View {
// HomeViewへ遷移する
VStack(spacing: 80) {
Button(action: {
// ログイン時の処理を書く
// ユーザーデフォルトにtokenを保持するとか
UserDefaults.standard.set("token", forKey: "apiToken")
self.pushSignIn = true
}) {
Text("ログインする")
}
NavigationLink(destination: ContentView(),
isActive: self.$pushSignIn) {
EmptyView()
}.hidden()
}
}
}
struct SignInView_Previews: PreviewProvider {
static var previews: some View {
SignInView()
}
}
1-3.新規登録画面とログイン画面を選択する画面
次は、ログインしていなかった時に最初に表示する画面を作成します。
ファイル名:SignView.swift
import SwiftUI
struct SignView: View {
var body: some View {
NavigationView {
VStack(spacing: 80) {
NavigationLink(destination: SignUpView()) {
Text("新規登録")
}
NavigationLink(destination: SignInView()) {
Text("ログイン")
}
}
}
}
}
struct SignView_Previews: PreviewProvider {
static var previews: some View {
SignView()
}
}
2.ログイン後の画面を作る
次に、ログイン後の画面を作成していきます。
2-1.HOME画面を作る
アプリのTOPのである、HOME画面を作成します。
ファイル名:HomeVIew.swift
import SwiftUI
struct HomeView: View {
var body: some View {
Text("HomeView!")
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
2-2.ログアウト画面を作る
ログアウトするための画面を作ります。
ファイル名:LogOutView.swift
import SwiftUI
struct LogOutView: View {
@State private var pushLogOut = false
var body: some View {
NavigationView {
// HomeViewへ遷移する
VStack(spacing: 80) {
Button(action: {
// ログイン時の処理を書く
// ユーザーデフォルトのtokenをクリアするとか
UserDefaults.standard.set(nil, forKey: "apiToken")
self.pushLogOut = true
}) {
Text("ログアウトする")
}
NavigationLink(destination: SignView(),
isActive: self.$pushLogOut) {
EmptyView()
}.hidden()
}
}
}
}
struct LogOutView_Previews: PreviewProvider {
static var previews: some View {
LogOutView()
}
}
2-3.TabVIewでHOME画面とログアウト画面を遷移できるようにする
ファイル名:ContentView.swift
import SwiftUI
struct ContentView: View {
var body: some View {
TabView {
HomeView()
.tabItem{
Text("HOME")
}
LogOutView()
.tabItem{
Text("ログアウト")
}
}
.edgesIgnoringSafeArea(.top)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
3.ログイン状態でログイン画面とログイン後の画面を出しわける
ファイル名:RootView.swift
import SwiftUI
struct RootView: View {
var body: some View {
Group {
if UserDefaults.standard.object(forKey: "apiToken") != nil {
ContentView()
} else {
SignView()
}
}
}
}
struct RootView_Previews: PreviewProvider {
static var previews: some View {
RootView()
}
}
ファイル名:sceneDelegate.swift(元々あるファイルです)
最初に呼び出すViewをRootViewに変更します。
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let contentView = RootView() ←ここを変更します
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
動かしてみる
さて、これでざっくりできたので実際に動かしてみます。
ちなみに、シミュレーターを使う場合、iOSが13.3だとNavigationViewがうまく動かないので13.2を使用してください。実機であれば13.3でも大丈夫です。
うまく動かないというのは、画面遷移してBackボタンで戻って来た後に、再度画面遷移しようとしても画面遷移してくれない。という動作です。
思った動作になってない。。。
画面遷移の度に、TabViewとNavigationViewが作られるので、TabBarとNavigationBarが入れ子でどんどん表示されてしまうし、SignViewに戻ってもTabバーが表示されてしまっている。
これをSwiftUIだけで簡単に解決する方法をこれからご紹介します。
(古いViewControllerとかは使いません!)
※ここから有料です※
解決方法
ここから先は
¥ 100
この記事が気に入ったらチップで応援してみませんか?