例えば、初回起動時の利用規約確認ページの表示やウォークスルーの表示、またそれらの画面からメイン画面への移動について
AppDelegateを介してwindow
のrootViewController
を切り替えたりしていたのですが、
メモリの関係であまり推奨されないらしい。
今回は専用のRootViewControllerを用意し、そのchildを挿げ替えるという方法があると知り、実践しました。
あわせて、起動時にはSplashViewControllerを用意して何らかのデータ取得や表示先画面の分岐を行っています。
今後Splash画面をアニメーションさせたくなったときにも入れやすそうです。
##前提情報
個人的な好みですが、随所でViewController
をVC
と略しています。
##まずは肝心のRootViewControllerの作成
RootVC.swift
import UIKit
final class RootVC: UIViewController {
// 現在表示しているViewControllerを示します
private var current: UIViewController
init() {
// 起動時最初の画面はSplashViewControllerを設定します
current = SplashVC()
super.init(nibName: nil, bundle: nil)
}
// init()を実装したことによる必須実装
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
// ViewControllerをRootVCの子VCとして追加
addChild(current)
current.view.frame = view.bounds
view.addSubview(current.view)
current.didMove(toParent: self)
}
/// RootVCの子VCを入れ替える=ルートの画面を切り替える
func transition(to vc: UIViewController) {
// 新しい子VCを追加
addChild(vc)
vc.view.frame = view.bounds
view.addSubview(vc.view)
vc.didMove(toParent: self)
// 現在のVCを削除する準備
current.willMove(toParent: nil)
// Superviewから現在のViewを削除
current.view.removeFromSuperview()
// RootVCから現在のVCを削除
current.removeFromParent()
// 現在のVCを更新
current = vc
}
// 移動したいViewControllerごとに用意しておくと簡単に使用できる
func transitionToMain() {
// 切り替えたい先のViewControllerを用意
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
transition(to: vc)
}
}
##AppDelegateで、最初に表示する画面をRootVCに設定する
AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// 以下を追加
// 最初に表示させるViewControllerにRootVCを指定する
window = UIWindow(frame: UIScreen.main.bounds)
window!.rootViewController = RootVC()
window!.makeKeyAndVisible()
return true
}
// その他メソッド省略…
}
extension AppDelegate {
/// AppDelegateのシングルトン
static var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
/// rootViewControllerは常にRootVC
var rootVC: RootVC {
return window!.rootViewController as! RootVC
}
}
##SplashVC
SplashVC.swift
import UIKit
/// 起動時、LauchScreenの後に表示される最初の画面。起動処理や遷移先画面の分岐を行う
final class SplashVC: UIViewController {
/// 処理中を示すインジケーター
private lazy var activityIndicator: UIActivityIndicatorView = {
let indicator = UIActivityIndicatorView(style: .whiteLarge)
indicator.frame = view.bounds
indicator.backgroundColor = UIColor(white: 0, alpha: 0.4)
return indicator
}()
/// 処理中に表示させておくスプラッシュ画像。LaunchScreenでも同じ画像を指定しておく
private lazy var splashImage: UIImageView = {
let imageView = UIImageView(
image: UIImage(named: "Japanese01")
)
imageView.contentMode = .scaleAspectFill
imageView.frame = view.frame
return imageView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(splashImage)
view.addSubview(activityIndicator)
// 起動時に行いたい処理を実行する
// UsecaseなりPresenterなり・・
activityIndicator.startAnimating()
// 中略
// メイン画面へ移動
AppDelegate.shared.rootVC.transitionToMain()
}
}
###参考
https://medium.com/@stasost/ios-root-controller-navigation-3625eedbbff