AdventCalendar
iOS
Swift

RootViewの切り替えにUIPageViewControllerが使いやすかった話

More than 1 year has passed since last update.

最近教えて頂いたTipsなのですが、実際に使ってみて良かったので共有記事です。

皆さん、ログイン・ログアウトした時にメインのコンテンツとの画面切替ってどうやって実装されてますか?

調べてみて見かけるのはRootViewControllerを切り替える方法とかですかね、でもこの方法だとアニメーションが元々無いので自前で書かなくちゃいけなかったり、、、

そんな時に今回の主役UIPageViewControllerの出番です!

特別難しい事はしていないので、コードを見てもらった方が分かりやすいと思います。

BasePageViewControllerStoryboardを起動時のStoryboardに設定しています。


BasePageViewController

import UIKit

extension Notification.Name {
static let pushToLogin = Notification.Name("PushToLogin")
static let pushToMainContents = Notification.Name("PushToMainContents")
}

class BasePageViewController: UIPageViewController {

override func viewDidLoad() {
super.viewDidLoad()

NotificationCenter.default.addObserver(self, selector: #selector(self.pushTologin(_:)), name: .pushToLogin, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.pushToMainContents(_:)), name: .pushToMainContents, object: nil)

if ログインしているかの条件 {
pushToMainContents()
} else {
pushTologin()
}
}

deinit {
NotificationCenter.default.removeObserver(self)
}

func pushTologin(_ notification: Notification? = nil) {
guard let login = login() else {
return
}
self.setViewControllers([login], direction: .forward, animated: true, completion: nil)
}

func pushToMainContents(_ notification: Notification? = nil) {
guard let mainContents = mainContents() else {
return
}
self.setViewControllers([mainContents], direction: .forward, animated: true, completion: nil)
}

private func login() -> UINavigationController? {
let loginStoryboard = UIStoryboard(name: "Login", bundle: nil)
guard let navigation = loginStoryboard.instantiateInitialViewController() as? UINavigationController else {
return nil
}
return navigation
}

private func mainContents() -> UINavigationController? {
let mainContentsStoryboard = UIStoryboard(name: "MainContents", bundle: nil)
guard let navigation = mainContentsStoryboard.instantiateInitialViewController() as? UINavigationController else {
return nil
}
return navigation
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}


ログイン画面

import UIKit

class LoginViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

}

// ログイン完了 → メインコンテンツ画面へ
func pushToMainContents() {
NotificationCenter.default.post(name: .pushToMainContents, object: nil)
}
}


メインコンテンツ画面

import UIKit

class MainContentsViewController: UIViewController {

override func viewDidLoad() {
super.viewDidLoad()

}

// ログアウト → ログイン画面へ
func pushToLogin(_ sender: UIButton) {
NotificationCenter.default.post(name: .pushToLogin, object: nil)
}
}

ViewControllerを切り替える時にBasePageViewControllerに対してNotificationを送っています。

PageViews.gif

使いどころとしては、BaseになっているViewControllerを切り替えたい場合や起動時に任意の画面を開きたい(URLスキームLocal,Remote通知からの起動等)時などに簡単にできるかと思います。


良かった点



  • UINavigationControllerUITabBarControllerでもsetViewControllersできるものだったら使用できる


  • UIPageViewControllerが持っているNavigationのPushの様な遷移を使って違和感なく遷移できる

  • 遷移先の画面に値を渡すこともできる(NofiticationobjectUserInfoにセットしてPageViewControllerで渡す)


イケてなかった点



  • ModalViewからの画面切り替えができない

    ※ 以下の様に閉じた後に処理をしないと動かない、起動時の画面遷移も同じなのでその場合はModalを破棄してからでないと、、、

dismiss(animated: true, completion: {

NotificationCenter.default.post(name: .pushToLogin, object: nil)
})

UIPageViewControllerの本来の使い方とは違いますが、自分は結構気に入っていて同じようなところで迷っている方の選択肢の一つになれたら幸いです。

最後に載せる程でもない簡単なサンプルはこちら → BasePageViewSample