[iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.
소개
로그인/로그아웃에 의해 화면을 전환하고 싶은 상황은 자주 있다고 생각합니다.
UIWindow의 rootViewController를 바꾸어 앱 어디서나 화면을 전환할 수 있도록 해 보았습니다.
아래 GIF 이미지와 같이 앱의 화면 전환을 구현합니다.
환경
[Xcode] 버전 12.4
[Swift] 버전 5.3.2
[iOS] 14.4
[MacOS] 10.15.7
구현 절차
[Xcode] 버전 12.4
[Swift] 버전 5.3.2
[iOS] 14.4
[MacOS] 10.15.7
구현 절차
rootViewController를 직접 전환하는 것은 그다지 권장되지 않는 것 같습니다. rootViewController의 하위 ViewController를 전환하고 rootViewController를
RootViewController
로 항상 설정합니다.이유는 메모리의 관계로, , 라고 하는 기사를 보았던 적이 있습니다만, 나 자신이 그 내용을 제대로 이해하고 있지 않기 때문에, 어디까지나 화면을 전환하는 1 수법으로서 도입하고 싶습니다.
SplashViewController
)을 만들고 전환 대상 화면을 전환합니다.여기의 내용은 생략합니다.
이 앱에는 SceneDelegate가 필요하지 않으므로 SceneDelegate를 삭제하고 AppDelegate를 통해 Window의 rootViewController를 가져옵니다. iOS13 이상에서 SceneDelegate를 사용하지 않고 AppDelegate를 사용하는 방법에 대한 설명은 이 기사에서는 생략합니다.
이 기사 가 알기 쉬웠으므로 참고로 했습니다.
RootViewController
RootViewControllerimport UIKit
final class RootViewController: UIViewController {
//現在のアプリケーションの状態を追跡するために、現在のViewControllerを指す変数を作成
private var current = UIViewController()
override func viewDidLoad() {
super.viewDidLoad()
//viewをロードするとすぐに呼ばれるSplashViewControllerを準備する
current = SplashViewController()
addChild(current)
current.view.frame = view.bounds
view.addSubview(current.view)
current.didMove(toParent: self)
}
//メイン画面への遷移メソッド
func switchToMainScreen() {
let mainViewController = MainViewController()
let new = UINavigationController(rootViewController: mainViewController)
animateFadeTransition(to: new)
}
//ログイン画面へ遷移するメソッド
func switchToLogin() {
let loginViewController = LoginViewController()
let new = UINavigationController(rootViewController: loginViewController)
animateFadeTransition(to: new)
}
//メイン画面に遷移する際のアニメーションメソッド
private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
current.willMove(toParent: nil)
addChild(new)
//ページ遷移
transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: {}) { (completed) in
self.current.removeFromParent()
new.didMove(toParent: self)
self.current = new
//完了
completion?()
}
}
//上記遷移メソッドの中身の各コードを説明 (showLoginScreen()というメソッドがあると仮定します)
func showLoginScreen() {
//遷移先のViewControllerオブジェクトを作成
let loginViewController = LoginViewController()
let new = UINavigationController(rootViewController: loginViewController)
//それをRootViewControllerの子ViewControllerとして追加
addChild(new)
//Viewのフレームを位置合わせ
new.view.frame = view.bounds
//そのビューをaddSubView
view.addSubview(new.view)
//新しいViewControllerを追加した直後に呼び出す必要あり
new.didMove(toParent: self)
//willMoveを呼び出して、現在の子ViewControllerを削除する準備
current.willMove(toParent: nil)
//現在のビューをスーパービューから削除
current.view.removeFromSuperview()
//現在の子ViewControllerを親のRootViewController切り離す
current.removeFromParent()
//最後に現在の子viewControllerを更新することを忘れずに。
current = new
}
SplashViewController
SplashViewController
import UIKit
//ユーザーの状況によって、アプリ起動後の遷移先を切り替える
final class SplashViewController: UIViewController {
//処理進行を示すインジケータ
private lazy var activityIndicator: UIActivityIndicatorView = {
let activityIndicator = UIActivityIndicatorView(style: .large)
activityIndicator.frame = view.bounds
activityIndicator.color = .white
activityIndicator.backgroundColor = UIColor(white: 0.5, alpha: 0.4)
return activityIndicator
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(activityIndicator)
//アプリ起動時の画面切り替え
makeScreenTransition()
}
//ユーザーの状態によって画面を切り替えるメソッド
private func makeScreenTransition() {
//1秒後に止まる遅延処理
activityIndicator.startAnimating()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) {
self.activityIndicator.stopAnimating()
//今回はログイン状況をデバイスに保存している想定です
if UserDefaults.standard.bool(forKey: "isLogin") {
//メイン画面へ
AppDelegate.shared.rootViewController.switchToMainScreen()
} else {
//ログイン画面へ
AppDelegate.shared.rootViewController.switchToLogin()
}
}
}
}
AppDelegate
AppDelegate 싱글 톤을 만들어 어디서나 호출하여 화면을 전환 할 수 있습니다.
AppDelegateimport UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
//RootViewControllerを設定
window.rootViewController = RootViewController()
window.makeKeyAndVisible()
return true
}
}
extension AppDelegate {
//シングルトン
static var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
var rootViewController: RootViewController {
return window!.rootViewController as! RootViewController
}
}
마지막으로
RootViewController가 화면 전환을 담당하기 때문에 저처럼 단순한 디자인의 앱을 개발하고 있는 경우에는 구현, 관리의 쉬운 방법이라고 생각했습니다.
앞으로 더 복잡한 상황에 대한 대응과 더 나은 구현 방법이 있다면 배우고 기사로 갈 수 있다고 생각합니다.
참고문헌
이 기사는 다음 정보를 참고했습니다.
- iOS: Root Controller Navigation
- iOS13에서 SceneDelegate를 사용하지 않고 앱 만들기
Reference
이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/mtkmr/items/6840fc5c1ac342a55055
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import UIKit
final class RootViewController: UIViewController {
//現在のアプリケーションの状態を追跡するために、現在のViewControllerを指す変数を作成
private var current = UIViewController()
override func viewDidLoad() {
super.viewDidLoad()
//viewをロードするとすぐに呼ばれるSplashViewControllerを準備する
current = SplashViewController()
addChild(current)
current.view.frame = view.bounds
view.addSubview(current.view)
current.didMove(toParent: self)
}
//メイン画面への遷移メソッド
func switchToMainScreen() {
let mainViewController = MainViewController()
let new = UINavigationController(rootViewController: mainViewController)
animateFadeTransition(to: new)
}
//ログイン画面へ遷移するメソッド
func switchToLogin() {
let loginViewController = LoginViewController()
let new = UINavigationController(rootViewController: loginViewController)
animateFadeTransition(to: new)
}
//メイン画面に遷移する際のアニメーションメソッド
private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
current.willMove(toParent: nil)
addChild(new)
//ページ遷移
transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: {}) { (completed) in
self.current.removeFromParent()
new.didMove(toParent: self)
self.current = new
//完了
completion?()
}
}
//上記遷移メソッドの中身の各コードを説明 (showLoginScreen()というメソッドがあると仮定します)
func showLoginScreen() {
//遷移先のViewControllerオブジェクトを作成
let loginViewController = LoginViewController()
let new = UINavigationController(rootViewController: loginViewController)
//それをRootViewControllerの子ViewControllerとして追加
addChild(new)
//Viewのフレームを位置合わせ
new.view.frame = view.bounds
//そのビューをaddSubView
view.addSubview(new.view)
//新しいViewControllerを追加した直後に呼び出す必要あり
new.didMove(toParent: self)
//willMoveを呼び出して、現在の子ViewControllerを削除する準備
current.willMove(toParent: nil)
//現在のビューをスーパービューから削除
current.view.removeFromSuperview()
//現在の子ViewControllerを親のRootViewController切り離す
current.removeFromParent()
//最後に現在の子viewControllerを更新することを忘れずに。
current = new
}
SplashViewController
import UIKit
//ユーザーの状況によって、アプリ起動後の遷移先を切り替える
final class SplashViewController: UIViewController {
//処理進行を示すインジケータ
private lazy var activityIndicator: UIActivityIndicatorView = {
let activityIndicator = UIActivityIndicatorView(style: .large)
activityIndicator.frame = view.bounds
activityIndicator.color = .white
activityIndicator.backgroundColor = UIColor(white: 0.5, alpha: 0.4)
return activityIndicator
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
view.addSubview(activityIndicator)
//アプリ起動時の画面切り替え
makeScreenTransition()
}
//ユーザーの状態によって画面を切り替えるメソッド
private func makeScreenTransition() {
//1秒後に止まる遅延処理
activityIndicator.startAnimating()
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(1)) {
self.activityIndicator.stopAnimating()
//今回はログイン状況をデバイスに保存している想定です
if UserDefaults.standard.bool(forKey: "isLogin") {
//メイン画面へ
AppDelegate.shared.rootViewController.switchToMainScreen()
} else {
//ログイン画面へ
AppDelegate.shared.rootViewController.switchToLogin()
}
}
}
}
AppDelegate
AppDelegate 싱글 톤을 만들어 어디서나 호출하여 화면을 전환 할 수 있습니다.
AppDelegateimport UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
//RootViewControllerを設定
window.rootViewController = RootViewController()
window.makeKeyAndVisible()
return true
}
}
extension AppDelegate {
//シングルトン
static var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
var rootViewController: RootViewController {
return window!.rootViewController as! RootViewController
}
}
마지막으로
RootViewController가 화면 전환을 담당하기 때문에 저처럼 단순한 디자인의 앱을 개발하고 있는 경우에는 구현, 관리의 쉬운 방법이라고 생각했습니다.
앞으로 더 복잡한 상황에 대한 대응과 더 나은 구현 방법이 있다면 배우고 기사로 갈 수 있다고 생각합니다.
참고문헌
이 기사는 다음 정보를 참고했습니다.
- iOS: Root Controller Navigation
- iOS13에서 SceneDelegate를 사용하지 않고 앱 만들기
Reference
이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/mtkmr/items/6840fc5c1ac342a55055
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
self.window = window
//RootViewControllerを設定
window.rootViewController = RootViewController()
window.makeKeyAndVisible()
return true
}
}
extension AppDelegate {
//シングルトン
static var shared: AppDelegate {
return UIApplication.shared.delegate as! AppDelegate
}
var rootViewController: RootViewController {
return window!.rootViewController as! RootViewController
}
}
RootViewController가 화면 전환을 담당하기 때문에 저처럼 단순한 디자인의 앱을 개발하고 있는 경우에는 구현, 관리의 쉬운 방법이라고 생각했습니다.
앞으로 더 복잡한 상황에 대한 대응과 더 나은 구현 방법이 있다면 배우고 기사로 갈 수 있다고 생각합니다.
참고문헌
이 기사는 다음 정보를 참고했습니다.
- iOS: Root Controller Navigation
- iOS13에서 SceneDelegate를 사용하지 않고 앱 만들기
Reference
이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://qiita.com/mtkmr/items/6840fc5c1ac342a55055
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
Reference
이 문제에 관하여([iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/mtkmr/items/6840fc5c1ac342a55055텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)