LoginSignup
305

More than 1 year has passed since last update.

カスタムContainer View Controllerを作る

Last updated at Posted at 2014-02-25

AppleのiOS View Controllerプログラミングガイドは色々と参考になるものが多かったです。
まだ読んでない人はぜひ一度読んでみてください。設計する上でもとても有用な情報が載っています。

##Container View Controller(コンテナ)

Container View Controllerは、コンテナとしての役割を担うViewControllerです。
すでにあるものとしてはNavigationViewControllerTabViewControllerがそれに当たります。
つまり、子となるViewControllerを内包するちょっと特殊なViewControllerです。

###コンテナViewControllerの役割

コンテナというくらいなので、なにかしらのViewController群をまとめる役割を持ちます。
NavigationViewControllerであればスタックとしてViewControllerを管理し、TabViewControllerであれば並列関係のViewContrllerを管理します。

そして必要であれば、コンテナViewController独自のビュー領域(ナビゲーションバーやタブバーみたいなもの)を用意して、それを利用して内包しているViewControllerを表示したり、ということもできます。

ただ、実装を見ると分かりますが、基本的にはUIViewControllerのサブクラスでしかないので、コンテナの中にコンテナが、という入れ子構造ももちろん実現することができます。

###コンテナViewControllerの作成手順

コンテナ用のViewControllerを作る際は、通常のViewControllerとは少し考慮することが変わります。
手順としては、

  1. addChildViewController:メソッドでViewControllerの親子関係を作る
  2. ViewControllerのviewを自身のviewのsubviewに追加する
  3. ViewControllerのdidMoveToParentViewController:メソッドを、自身を引数にして呼ぶ

という流れです。

(2)のview追加に関しては、通常のUIViewなどを管理するのと同じです。
(1)と(3)が特殊な部分ですが、よく考えればむずかしくありません。

ViewControllerを内包するということは親子関係を作るということ。
そのためのメソッドがaddChildViewController:メソッドです。
(逆に削除するにはremoveFromParentViewControllerメソッドを子ViewController側で呼びます)
このあたりはviewに対するaddSubviewremoveFromSuperview)などと同じ理屈ですね。

ちなみにaddChildViewController:を呼び出すと、自動的に、引数に渡されたViewControllerのwillMoveToParentViewController:メソッドが呼び出され、これからコンテナViewControllerの子要素になることが通知されるようになっています。

逆に、removeFromParentViewControllerを呼ぶと、didMoveToParentViewController:が呼ばれます。

####ライフサイクルはどうなる?

上記のメソッドを適切に呼び出すことで、普段使っているライフサイクル、viewDidLoadviewWillAppearなどのメソッドが順次呼び出されていきます。

###サンプルコード

Appleのプログラミングガイドのサンプルコードをコメントをつけつつ掲載します。
(サンプルはすべて、コンテナViewControllerのメソッドです)

####子のViewControllerを追加する

- (void)displayContentController:(UIViewController *)content
{
	// 自身のビューコントローラ階層に追加
	// 自動的に子ViewControllerの`willMoveToParentViewController:`メソッドが呼ばれる
	[self addChildViewController:content];

	// 子ViewControllerの`view`を自身の`view`階層に追加
	[self.view addSubview:content.view];

	// 子ViewControllerに追加が終わったことを通知する
	[content didMoveToParentViewController:self];
}

####子のViewControllerを削除する

- (void)hideContentController:(UIViewController *)content
{
	// これから取り除かれようとしていることを通知する(引数が`nil`なことに注意)
	[content willMoveToParentViewController:nil];

	// 子ViewControllerの`view`を取り除く
	[content.view removeFromSuperview];

	// 子ViewControllerを取り除く
	// 自動的に`didMoveToParentViewController:`が呼ばれる
	[content removeFromParentViewController];
}

####ViewControllerの入れ替わりをアニメーションさせる

NavigationViewControllerなどのように、ViewControllerの入れ替え時にアニメーションさせることもできます。

- (void)cycleFromViewController:(UIViewController *)oldC toViewController:(UIViewController *)newC
{
	// 古いViewControllerに取り除かれようとしていることを通知する
	[oldC willMoveToParentViewController:nil];

	CGFloat width  = self.view.bounds.size.width;
	CGFloat height = self.view.bounds.size.height;

	// アニメーションスタート位置を画面下部にする
	CGRect startFrame = CGRectMake(0, height, width, height);
	[self addChildViewController:newC];

	newC.view.frame = startFrame;
	CGRect endFrame = CGRectMake(0, 100, width, height);

	[self transitionFromViewController:oldC
						toViewController:newC
					 			 duration:0.25
								  options:0
						  	   animations:^{
									newC.view.frame = oldC.view.frame;
									oldC.view.frame = endFrame;
							   }
							completion:^(BOOL finished) {
								[oldC removeFromParentViewController];
								[newC didMoveToParentViewController:self];
							}];
}

transitionFromViewController:toViewController:duration:options:animations:completion:メソッドを使うことによって入れ替わりのアニメーションを実装することができます。

animations:にblocksを渡すことで、どういうアニメーションをさせるか、ということができます。
これを使えば、ちょっと変わったアニメーションをもったコンテナViewControllerが作れそうですね。

今回のサンプルはgithubにあげてみました。プログラミングガイドをほぼそのまま使ったものですが。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
305