Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Container View Controllerを
正しく使おう
potatotips (iOS/Android開発Tips共有会) 第14回
2015/2/18
@asakahara
自己紹介
id:sakahara
Twitter: @asakahara
・http://sakahara.hatenablog.jp/
・はてなのアプリケーションエンジニア
・はてなブックマークチームに所属
・iOS/Androidを主に担当
Container View Controllerのメリット
1. UINavigationController、UITabBarControllerのように独自の
transitionを組み込んでView Controllerを管理する仕組み...
今更ではありますが
Container View Controller
を正しく使えているでしょうか?
実装が間違っていてもちゃんと動くケースが
多いので意外に気づいてない方がいるかも
まずは基本からおさらい
コンテナへView Controllerを追加
1. addChildViewController:を呼び出す
そのタイミングで自動的に追加した子の
willMoveToParentViewController:が呼び出される
2. 子のビュー...
コンテナからView Controllerを削除
1. 子のwillMoveToParentViewController:を引数にnilを渡して
呼び出し、削除されることを通知する
2. 子のビューをビュー階層から削除する
3. 子のremov...
func transitionFromViewController(fromViewController: UIViewController,
toViewController: UIViewController) {
!
fromViewCo...
transitionFromViewController:
transitionFromViewController:toViewController:duration:
options:animations:completion:
!
このメ...
isMovingFromParentViewController
親から削除中かどうかを判定をする
viewWillDisappear:、もしはviewDidDisappear: から呼ばれた場合の
みYESを返す
!
isMovingToPa...
shouldAutomaticallyForwardAppearanceMethods
ドキュメントを見ると「このメソッドをオーバーライドして
NOを返すことで外観に関するコールバックの制御権を取得
できる」とか書いてある・・・
分かりにくい
...
簡単に言い直すと
shouldAutomaticallyForwardAppearanceMethodsをオーバーライ
ドしてNOを返すことでトランジションが発生した際の通知を子に自
動的に送らないようして、手動で行うようにする(デフォルトはY...
しかし・・・
•viewWillAppear:/DidAppear:
•viewWillAppear/DidDisappear:
!
を直接呼ぶのはNG
!
その代わりに子の
!
•beginAppearanceTransition:anima...
override func shouldAutomaticallyForwardAppearanceMethods() -> Bool {
return false
}
!
override func viewWillAppear(animat...
private func transition(from: UIViewController, to: UIViewController) {
if from == to { return }
!
from.beginAppearanceTra...
まとめ
• Container View Controllerへの追加や削除をする
際にいくつかの手続きがあることを知っておく
• これらのルールを守っておけば基本的に問題ない
• shouldAutomaticallyForwardAppea...
もっと詳しく知りたい方は
• iOS View Controllerプログラミングガイド
• UIViewController Class Reference
!
これらを読んでより理解を深めましょう
ご清聴ありがとうございました
Upcoming SlideShare
Loading in …5
×

Container View Controllerを正しく使おう

14,004 views

Published on

potatotips (iOS/Android開発Tips共有会) 第14回で使った資料

Published in: Technology
  • Be the first to comment

Container View Controllerを正しく使おう

  1. 1. Container View Controllerを 正しく使おう potatotips (iOS/Android開発Tips共有会) 第14回 2015/2/18 @asakahara
  2. 2. 自己紹介 id:sakahara Twitter: @asakahara ・http://sakahara.hatenablog.jp/ ・はてなのアプリケーションエンジニア ・はてなブックマークチームに所属 ・iOS/Androidを主に担当
  3. 3. Container View Controllerのメリット 1. UINavigationController、UITabBarControllerのように独自の transitionを組み込んでView Controllerを管理する仕組みを実装で きる Container View Controllerの初期化時に各View Controllerへ依存性の 注入を行えるメリットも 2. View Controllerから別のView Controllerを表示することが簡単に 実現できる 3. ログイン状態を確認してログイン画面を出すかその他の画面を出 すの切り替えが容易にできる かつてViewDidAppear:などでログインしてなかったらログイン画面の モーダルを出してたようなコードとおさらばできる
  4. 4. 今更ではありますが Container View Controller を正しく使えているでしょうか? 実装が間違っていてもちゃんと動くケースが 多いので意外に気づいてない方がいるかも まずは基本からおさらい
  5. 5. コンテナへView Controllerを追加 1. addChildViewController:を呼び出す そのタイミングで自動的に追加した子の willMoveToParentViewController:が呼び出される 2. 子のビューを自身のビュー階層に追加する 3. 子のdidMoveToParentViewController:を明示的に呼び出して、処理 が終了した旨のシグナルを送信する(transitionが無い場合、すぐに 呼び出す) addChildViewController(contentViewController) view.addSubview(contentViewController.view) contentViewController.didMoveToParentViewController(self)
  6. 6. コンテナからView Controllerを削除 1. 子のwillMoveToParentViewController:を引数にnilを渡して 呼び出し、削除されることを通知する 2. 子のビューをビュー階層から削除する 3. 子のremoveFromParentViewControllerを呼び出して、コン テナから削除する そのタイミングで子のdidMoveToParentViewController:が 自動的に呼び出される contentViewController.willMoveToParentViewController(nil) contentViewController.view.removeFromSuperview() contentViewController.removeFromParentViewController()
  7. 7. func transitionFromViewController(fromViewController: UIViewController, toViewController: UIViewController) { ! fromViewController.willMoveToParentViewController(nil) addChildViewController(toViewController) ! let width = view.bounds.size.width let height = view.bounds.size.height let startFrame = CGRectMake(0, height, width, height) ! toViewController.view.frame = startFrame let endFrame = CGRectMake(0, 100, width, height) ! transitionFromViewController(fromViewController, toViewController: toViewController, duration: 0.25, options: .TransitionNone, animations: { toViewController.view.frame = fromViewController.view.frame fromViewController.view.frame = endFrame }) { _ in fromViewController.removeFromParentViewController() toViewController.didMoveToParentViewController(self) } } Transitionについて
  8. 8. transitionFromViewController: transitionFromViewController:toViewController:duration: options:animations:completion: ! このメソッドは自動的に新しいビューを追加し、アニメーショ ン表示を行ってから古いビューを削除する。 そのためaddSubview:、removeFromSuperviewは不要 !
  9. 9. isMovingFromParentViewController 親から削除中かどうかを判定をする viewWillDisappear:、もしはviewDidDisappear: から呼ばれた場合の みYESを返す ! isMovingToParentViewController 親に追加中かどうかを判定をする viewWillAppear:、もしはviewDidAppear: から呼ばれた場合のみYES を返す !
  10. 10. shouldAutomaticallyForwardAppearanceMethods ドキュメントを見ると「このメソッドをオーバーライドして NOを返すことで外観に関するコールバックの制御権を取得 できる」とか書いてある・・・ 分かりにくい 更にこんな機能もあります
  11. 11. 簡単に言い直すと shouldAutomaticallyForwardAppearanceMethodsをオーバーライ ドしてNOを返すことでトランジションが発生した際の通知を子に自 動的に送らないようして、手動で行うようにする(デフォルトはYES) ! 子の下記メソッドを呼ぶタイミングを手動で調整できる • viewWillAppear/ViewDidAppear:animated • viewWillDisappear/ViewDidDisappear:animated • willRotateToInterfaceOrientation:duration: • willAnimateRotationToInterfaceOrientation:duration: • didRotateFromInterfaceOrientation:
  12. 12. しかし・・・ •viewWillAppear:/DidAppear: •viewWillAppear/DidDisappear: ! を直接呼ぶのはNG ! その代わりに子の ! •beginAppearanceTransition:animated: •endAppearanceTransition ! メソッドを呼び出すようにする
  13. 13. override func shouldAutomaticallyForwardAppearanceMethods() -> Bool { return false } ! override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) contentViewController?.beginAppearanceTransition(true, animated: animated) } ! override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) contentViewController?.endAppearanceTransition() } ! override func viewWillDisappear(animated: Bool) { super.viewWillDisappear(animated) contentViewController?.beginAppearanceTransition(false, animated: animated) } ! override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) contentViewController?.endAppearanceTransition() } 例えばこんな感じで
  14. 14. private func transition(from: UIViewController, to: UIViewController) { if from == to { return } ! from.beginAppearanceTransition(false, animated: false) to.beginAppearanceTransition(true, animated: false) ! from.view.removeFromSuperview() to.view.frame = view.bounds view.addSubview(to.view) ! from.endAppearanceTransition() to.endAppearanceTransition() } var selectedIndex: Int = 0 { didSet { transition(childViewControllers[oldValue] as UIViewController, to: childViewControllers[selectedIndex] as UIViewController) } } Viewの切り替えを行う例
  15. 15. まとめ • Container View Controllerへの追加や削除をする 際にいくつかの手続きがあることを知っておく • これらのルールを守っておけば基本的に問題ない • shouldAutomaticallyForwardAppearanceMetho dsでNOを返すことで、コールバックの制御を自 分でコントロールできることも知っておくとよい
  16. 16. もっと詳しく知りたい方は • iOS View Controllerプログラミングガイド • UIViewController Class Reference ! これらを読んでより理解を深めましょう
  17. 17. ご清聴ありがとうございました

×