なんか他にもっとスマートなやり方がある気がしているけど、とりあえずこうした、というメモ。
要件
今回やりたかったことは、
- UINavigationControllerのnavigationBarも含めた、画面全体を覆うように半透明の黒いビューを表示する
- その上にメニューとなるボタンを出し、そして回転に対応すること。
この「回転に対応する」という部分に苦労しました。
今回やった対応は以下の感じです。
対応した内容
まず、UIViewControllerを継承したサブクラス(CustomViewController
)を作ります。
その上で、メインとなるViewControllerからこのサブクラスを生成します。
ただ、メインのViewControllerはUINavigationControllerの子ViewControllerなので、これにaddChildViewController:
で追加してしまうとnavigationBarの中に入ってしまいます。
window
のsubViewに
そこで、以下のようにしてwindow
のsubViewにしました。
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
UIWindow *window = nil;
if ([appDelegate respondsToSelector:@selector(window)]) {
window = [appDelegate window];
}
else {
window = [[UIApplication sharedApplication] keyWindow];
}
CustomViewController *cvc = [[CustomViewController alloc] init];
[window addSubview:cvc.view];
回転処理
回転処理は、メインのViewControllerの回転に関するデリゲートメソッドをオーバーライドし、そのタイミングで以下のようにwindow
に追加したViewControllerのviewを操作しました。
// CustomViewController側
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
[UIView animateWithDuration:duration
animations:^{
CGRect frame = self.coverView.frame;
frame.size.width = self.view.bounds.size.width;
frame.size.height = self.view.bounds.size.height;
self.coverView.frame = frame;
self.coverView.center = self.view.center;
switch (toInterfaceOrientation) {
// 通常の状態
case UIInterfaceOrientationPortrait: {
self.coverView.transform = CGAffineTransformMakeRotation(0);
break;
}
// デバイスの左側が上の状態
case UIInterfaceOrientationLandscapeLeft: {
self.coverView.transform = CGAffineTransformMakeRotation(-M_PI / 2);
break;
}
// デバイスの右側が上の状態
case UIInterfaceOrientationLandscapeRight: {
self.coverView.transform = CGAffineTransformMakeRotation(M_PI / 2);
break;
}
}
}];
}
self.coverView
が、半透明の黒いビューの部分です。
これにボタンなどのメニューがsubViewとして追加されています。
上記のコードでこのcoverView
自体は回転しますが、見てもらうと分かる通りwidth/height
を操作しているので、subView
の位置がずれてしまいます。
なので、上記以外にもsubView
の位置も合わせて調整してやる必要があります。
本当は独立したViewControllerにも回転の制御を指定できればいいんですが・・・。