iOS/iPhone/iPad/watchOS/tvOS/MacOSX/Android プログラミング, Objective-C, Cocoa, Swiftなど
iOSのCocoa Touchフレームワークには、横並びの画面はTab Bar Controller、階層方向はNavigaton Controllerが用意されているので、画面管理はこれを使えばいいのだが、標準のUIと異なる画面遷移が必要になった際に困ってしまう。
そうなったら、自分でビューの登録削除を行って独自の画面遷移を実装する事になるのだが、せっかくのビューコントローラが有効に活用できなくて残念と感じた事はないだろうか?
iOS 5から、Tab Bar Controllerの様なコンテナViewControllerを独自に実装できる機能がUIViewControllerに追加されたので、それを使って横並びの画面管理を実装してみた。
iOS 5から追加されたコンテナ機能の為のメソッドは、以下の4つ。
作成する画面は、灰色のTOPのビューコントローラの配下に赤と青の子ビューコントローラがあって、子っビューコントローラの画面上のボタンを押下すると、画面が切り替わるというものだ。
子ビューコントローラは、それぞれ、独立したStoryboardで作成した。
UIStoryboard *oneStoryboard = [UIStoryboard storyboardWithName:@"OneStoryboard" bundle:nil];
UIStoryboard *twoStoryboard = [UIStoryboard storyboardWithName:@"TwoStoryboard" bundle:nil];
OneViewController *oneViewController = [oneStoryboard instantiateInitialViewController];
TwoViewController *twoViewController = [twoStoryboard instantiateInitialViewController];
コンテナビューコントローラに子ビューコントローラを登録。
[self addChildViewController:oneViewController];
[self addChildViewController:twoViewController];
oneViewController.cvcViewController = self;
twoViewController.cvcViewController = self;
子ビュコントローラがコンテナビューコントローラ配下になった際の処理は、didMoveToParentViewController:に記述するのだが、コンテナビューコントローラの画面表示が完了した後でないと、addChildViewController:時に自動で呼ばれないようなので、呼ぶ必要がある場合は、自分で呼ぶ事になるようだ。
[oneViewController didMoveToParentViewController:self];
[twoViewController didMoveToParentViewController:self];
ビューコントローラの階層構造を作っても、Viewとは無関係の話。なので、最初の画面を表示するコードを記述しないといけない。
self.selectedViewController = [self.childViewControllers objectAtIndex:0];
[self.view addSubview:self.selectedViewController.view];
画面を切り替えるのは、メソッドtoggleVCで行っている。UIViewControllerには、画面切り替え用のメソッド– transitionFromViewController:toViewController:duration:options:animations:completion:を用意しているが、用意されている画面遷移のアニメーションでないのを望む場合は、自分でなんとかしないといけないようだ。それが、else分の青(two)から赤(one)に切り替わるコードとなる。
- (void)toggleVC
{
UIViewController *oneViewController = [self.childViewControllers objectAtIndex:0];
UIViewController *twoViewController = [self.childViewControllers objectAtIndex:1];
if (self.selectedViewController == oneViewController) {
[self transitionFromViewController:oneViewController
toViewController:twoViewController
duration:1.0
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:NULL
completion:NULL];
self.selectedViewController = twoViewController;
}
else {
[UIView animateWithDuration:1.0
animations:^{
CGPoint fromPt = twoViewController.view.layer.position;
CGPoint toPt = CGPointMake(fromPt.x, (fromPt.y * -1.0));
twoViewController.view.layer.position = toPt;
}
completion:^(BOOL finished) {
/* 元の位置の戻す */
CGPoint fromPt = twoViewController.view.layer.position;
CGPoint toPt = CGPointMake(fromPt.x, (fromPt.y * -1.0));
twoViewController.view.layer.position = toPt;
/* 画面遷移(アニメーションなし) */
[self transitionFromViewController:twoViewController
toViewController:oneViewController
duration:0.0
options:0
animations:NULL
completion:NULL];
}];
self.selectedViewController = oneViewController;
}
}