UISplitViewController の回転状態を把握する : Objective-C プログラミング

PROGRAM


UISplitViewController の回転状態を把握する

iPad で UISplitViewController を使用していて、Detail View Controller の回転状態を確認しようとしたときに、それの正しい回転方向を取得することができないことがありました。

Detail View の正しい回転方向を取得できない

回転状態が検出できないのは、実装方法にも依るのですけど、とりあえず自分の場合は UISplitViewController の Master View Controller と Detail View Controller との両方に、まずは UINavigationController を設置しました。

Master View Controller の UINavigationController 上では UITableViewController によるメニュー画面が表示されています。Detail View Controller の UINavigationController では、真っ白なビューが表示された UIViewController を配置しています。

そして、メニューのセルをクリックすると、Detail View Controller の先にある UIViewController の view に対して addSubView を使って、表示したい新しい UIViewController の view を追加する、といった実装方法です。

ただ、このようにした場合、たとえば現在表示中の UIViewController を aViewController としたときに、この aViewController の interfaceOrientation を取得しても、常に初期化された当時の回転方向が取得されてしまいました。

 

調べてみると、これはおそらく、aViewController の view を subView として Detail View Controller に登録しただけだったため、回転情報が伝わってくるのが Detail View Controller までとなっている様子です。

ちなみにこのとき、この方法では aViewController に対して "willAnimateRotationToInterfaceOrientation:duration:" 等といった回転を検知するメソッドも呼び出されません。

このように、addSubView によって追加されただけの aViewController では、UIViewController が回転処理を正しく制御できないことを踏まえておかないと、プログラミングも混乱してきてしまいます。

Detail View の回転方向を取得する

今回の場合のような実装で正しい回転情報を取得するには、aViewController ではなく、その下の Detail View Controller の interfaceOrientation を参照する必要があるようでした。

Detail View Controller へすぐにアクセスできれば話は簡単なのですけど、通常は aViewController からは簡単には Detail View Controller を参照することはできない場合も多いと思います。

 

iPad アプリの場合には、次のようにすることで、どこからでも Detail View Controller へたどり着くことができました。

UIInterfaceOrientation orientation;

 

// UISplitViewController はいちばん最初の ViewController になるはずなので、まずはそれを取得します。

UIViewController* rootViewController = [[[UIApplication sharedApplication] keyWindow] rootViewController];

 

// いちばん最初のビューが UISplitViewController であれば、その Detail View Controller を取得します。

if ([rootViewController isKindOfClass:[UISplitViewController class]])

{

// Detail View Controller は UISplitViewController の最後のビューになります。

UIViewController* detailViewController = [[(UISplitViewController*)rootViewController viewControllers] lastObject];

 

// Detail View Controller の回転方向を取得して、それを、その上に乗っている aViewController の方向とみなします。

orientation = detailViewController.interfaceOrientation;

}

このようにして回転方向を取得してみたところ、適切な回転情報を取得することができるようになりました。

ちなみにこのとき、UISplitViewController の Detail View Controller では、回転方向が "UIInterfaceOrientationPortrait" か "UIInterfaceOrientationLandscapeLeft" のどちらかになる様子です。

デバイス自体がたとえば "UIDeviceOrientationPortraitUpsideDown" を向いていても、Detail View Controller の方向は UIInterfaceOrientationPortrait" になる感じで、そういえばあまり深く考えたことがなかったのですけど、UIViewController の方向って、言われてみれば確かに視覚的にはそのどちらかですね。

iOS 5 で実装する場合

iOS 5 で UISplitViewController を実装する場合には、iOS 5.0 から利用可能になった UIViewController の "addChildViewController:" を使用することで、回転情報を適切に伝えることができる様子です。

たとえば、現在表示中のビューが oldViewController だったとして、Detail View Controller に設定された UIViewController で、次のような感じにして、表示ビューを切り替えます。

// たとえば表示したい UIView を Nib から作成します。

UIViewController* nextViewController = [[UIViewController alloc] initWithNibName:@"aViewController" bundle:nil];

 

// 古いビューを取り除きます。

[oldViewController.view removeFromSuperview];

[oldViewController removeFromParentViewController];

 

// タイトルを表示したいビューのものに切り替えます。

self.title = nextViewController.title;

 

// 新しいビューを表示します。

[self addChildViewController:nextViewController];

[self.view addSubview:nextViewController.view];

Detail View Controller に表示している UIViewController で、上記のように "addSubview:" するのに加えて、"addChildViewController:" をすることで、新しく追加されたサブビューコントローラーにも、回転情報が正しく通知されるようにできる様子でした。

[ もどる ]