[iOS] RootViewController를 구현하여 화면을 전환해 보았습니다.

19138 단어 iOSSwift

소개



로그인/로그아웃에 의해 화면을 전환하고 싶은 상황은 자주 있다고 생각합니다.
UIWindow의 rootViewController를 바꾸어 앱 어디서나 화면을 전환할 수 있도록 해 보았습니다.
아래 GIF 이미지와 같이 앱의 화면 전환을 구현합니다.


환경



[Xcode] 버전 12.4
[Swift] 버전 5.3.2
[iOS] 14.4
[MacOS] 10.15.7

구현 절차


  • UIWindow 의 rootViewController 로 설정하기 위한, RootViewController 를 작성
    rootViewController를 직접 전환하는 것은 그다지 권장되지 않는 것 같습니다. rootViewController의 하위 ViewController를 전환하고 rootViewController를 RootViewController로 항상 설정합니다.
    이유는 메모리의 관계로, , 라고 하는 기사를 보았던 적이 있습니다만, 나 자신이 그 내용을 제대로 이해하고 있지 않기 때문에, 어디까지나 화면을 전환하는 1 수법으로서 도입하고 싶습니다.
  • 이번에는 응용 프로그램 시작 화면 (SplashViewController)을 만들고 전환 대상 화면을 전환합니다.
  • 로그인 화면과 메인 화면은 NavigationBar에 제목이 나오는 단순한 것을 만들고 있습니다.
    여기의 내용은 생략합니다.

  • 이 앱에는 SceneDelegate가 필요하지 않으므로 SceneDelegate를 삭제하고 AppDelegate를 통해 Window의 rootViewController를 가져옵니다. iOS13 이상에서 SceneDelegate를 사용하지 않고 AppDelegate를 사용하는 방법에 대한 설명은 이 기사에서는 생략합니다.
    이 기사 가 알기 쉬웠으므로 참고로 했습니다.

    RootViewController



    RootViewController
    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



    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 싱글 톤을 만들어 어디서나 호출하여 화면을 전환 할 수 있습니다.

    AppDelegate
    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를 사용하지 않고 앱 만들기

    좋은 웹페이지 즐겨찾기