こんにちは。きんくまです。
今回はContainerViewです。
ContainerViewを使うと親子関係を持つViewControllerをInterface Builder上で簡単に設定できます。
こういうUIのやつ
IB上ではこう表示されます。
ただ、IB上でこのように設定してしまうと、子供側のStoryboardの再利用が難しい気がしました。
基本的にStoryboardは分割しておいた方が管理が楽なので、子供は子供だけのStoryboardファイルにして、それを親側に埋め込みたいです。
それで、いろいろと試行錯誤していて、なんとかわかったのでまとめておこうかと。
詳しいことはAppleさんのドキュメントを見てください。
>> Implementing a Container View Controller
StoryboardではContainerViewは使わずにUIViewを使う
Storyboard上のContainerViewというのは、UIContainerViewという特別なクラスがあるわけではなく、普通のUIViewのようです。
なので、親側で子供のViewを埋め込むのはUIViewにします。
今回は 親、子供、孫の3段階の親子関係を持つようにするサンプルを作りました。
親です。
親はUINavigationControllerの中に埋め込まれている設定にしました。実際のアプリはほとんどこれに埋め込まれていることが多いと思ってそうしています。
親には上下2つのContainerView(実際にはUIView)を配置しました。
子供です。
子供には左右2つのContainerView(実際にはUIView)を配置しました。
孫です。
これがコンテンツとなります。TL = TopLeft, TR = TopRight, BL = BottomLeft, BR = BottomRightです。
四隅のテキストには外枠に対して1pxのマージンを設けてあります。
完成図です。親の中に子供、子供の中に孫を入れるとこうなります。
子供の背景色を半透明にして、孫の背景色をなしにしているので、色が混じって見えます。
完成図を横向きにした場合です。
それぞれのStoryboardは独立していますので、入れ子関係の組み合わせはあとでわりと簡単に変更することができます。
たとえば、孫のViewControllerを親に直接入れる2階層にするとか。
コードをみてみる
さきほどのAppleさんのドキュメントを見ると、ContainerViewのように親子関係をもたせるにはこんな感じにやればいいようです。
func displayContentController(content:UIViewController, container:UIView){ addChildViewController(content) content.view.frame = container.bounds container.addSubview(content.view) content.didMoveToParentViewController(self) }
もし、親子関係を解除する場合はこっち
func hideContentController(content:UIViewController){ content.willMoveToParentViewController(self) content.view.removeFromSuperview() content.removeFromParentViewController() }
このへんはそういう作法だと思うので、特に何も考えませんw
親のコード
class ViewController: UIViewController { @IBOutlet weak var topContainer:UIView! @IBOutlet weak var bottomContainer:UIView! var topHorizontalController:HorizontalViewController? var bottomHorizontalController:HorizontalViewController? override func viewDidLoad() { super.viewDidLoad() title = "Hello Container" topHorizontalController = createHorizontalViewController("Top") displayContentController(topHorizontalController!, container: topContainer) bottomHorizontalController = createHorizontalViewController("Bottom") displayContentController(bottomHorizontalController!, container: bottomContainer) } func createHorizontalViewController(containerTitle:String)->HorizontalViewController{ let sb:UIStoryboard = UIStoryboard(name: "HorizontalViewController", bundle: nil) let hController:HorizontalViewController = sb.instantiateInitialViewController() as! HorizontalViewController hController.containerTitle = containerTitle return hController } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func displayContentController(content:UIViewController, container:UIView){ addChildViewController(content) content.view.frame = container.bounds container.addSubview(content.view) content.didMoveToParentViewController(self) } func hideContentController(content:UIViewController){ content.willMoveToParentViewController(self) content.view.removeFromSuperview() content.removeFromParentViewController() } }
子供のコード
import UIKit class HorizontalViewController: UIViewController { @IBOutlet weak var leftContainer:UIView! @IBOutlet weak var rightContainer:UIView! var leftSampleController:SampleViewController? var rightSampleController:SampleViewController? var containerTitle:String? override func viewDidLoad() { super.viewDidLoad() leftSampleController = createSampleViewController("\(containerTitle!) Left") displayContentController(leftSampleController!, container: leftContainer) rightSampleController = createSampleViewController("\(containerTitle!) Right") displayContentController(rightSampleController!, container: rightContainer) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func createSampleViewController(viewTitle:String)->SampleViewController{ let sb:UIStoryboard = UIStoryboard(name: "SampleViewController", bundle: nil) let sampleController:SampleViewController = sb.instantiateInitialViewController() as! SampleViewController sampleController.buttonTitle = viewTitle return sampleController } func displayContentController(content:UIViewController, container:UIView){ addChildViewController(content) content.view.frame = container.bounds container.addSubview(content.view) content.didMoveToParentViewController(self) } func hideContentController(content:UIViewController){ content.willMoveToParentViewController(self) content.view.removeFromSuperview() content.removeFromParentViewController() } }
孫のコード
class SampleViewController: UIViewController { @IBOutlet weak var centerButton:UIButton! var buttonTitle:String? override func viewDidLoad() { super.viewDidLoad() if buttonTitle != nil { setCenterButtonLabel(buttonTitle!) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() } func setCenterButtonLabel(text:String){ centerButton.setTitle(text, forState: UIControlState.Normal) } }
ファイルの階層構造
まとめ
分割管理できて、再利用できるようになったのでうれしいです。
あとどうしてなのかわからないのですが、デバイスを横向きにしても四隅がぴったりはまっているので、AutoLayoutも設定されているっぽいです。
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ