iOS6 rotation addendum

by Andy

I wrote previously about handling rotation in iOS6, notably with respect to modal dialogs which I determined are best handled as child view controllers. I recently extended the app that brought to light a situation I wasn’t handling and therefore I need to add an addendum to that post.

The new feature I added was a full screen modal that I did not want to be rotated on the iPhone. The layout was primarily data entry and hence a keyboard would over a significant portion of the screen, so the flow really dictated a portrait only display. I had to tweak the code to prohibit the rotation on this particular view controller.

A very quick reading of the documentation would suggest that adding the following code to the modal view controller would do the job.

- (BOOL)shouldAutorotate {
return IPAD ? YES : NO;
}
- (NSUInteger)supportedInterfaceOrientations {
return IPAD ? UIInterfaceOrientationMaskAll : UIInterfaceOrientationMaskPortrait;
}
view raw gistfile1.m hosted with ❤ by GitHub

We are saying that this view only supports portrait on the iPhone and that we should not auto-rotate. However this does not work as expected, because under iOS6 container view controllers (such as UINavigationController) do not consult their children about rotation events. The root view controller application in my app is a UINavigationController and so the determination as to rotate or not does not go deeper into the view hierarchy and therefore the autoRotate and supportInterfaceOrientations methods on my modal view controller are never called. I am using a base UINavigationController so the rotation methods fall back to their defaults, which on the iPhone is to allow everything except upside down portrait.

The first step is to force the UINavigationController consult its top level view controller about rotation, which is easily managed by a category:

@implementation UINavigationController (Rotation)
// iOS 6
- (BOOL)shouldAutorotate {
return [[self topViewController] shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations {
return [[self topViewController] supportedInterfaceOrientations];
}
@end
view raw gistfile1.m hosted with ❤ by GitHub

My top level view controller is also a container that presents modals as child view controllers, so it needs to consult its children too.

- (BOOL)shouldAutorotate {
BOOL autoRotate = YES;
for (UIViewController *vc in [self childViewControllers]) {
autoRotate = autoRotate && [vc shouldAutorotate];
}
return autoRotate;
}
- (NSUInteger)supportedInterfaceOrientations {
NSUInteger supported = IPAD ? UIInterfaceOrientationMaskAll : UIInterfaceOrientationMaskAllButUpsideDown;
for (UIViewController *vc in [self childViewControllers]) {
supported &= [vc supportedInterfaceOrientations];
}
return supported;
}
view raw gistfile1.m hosted with ❤ by GitHub

So finally this code will ask the modal view controller about rotation and will receive an appropriate answer. This new modal will prohibit rotation, but other simpler and smaller modals still can be rotated.

Advertisement