Reputation: 1382
I have a child UIViewController
with that's part of a hierarchy with a UITabBarController
and a UINavigationBarController
. Let's call it ChildViewController
; then my hierarchy looks like:
UITabBarController
|
UINavigationViewController [tab 1]
|
SomeParentViewController
|
SomeOtherParentViewController
|
ChildViewController
Now I want only ChildViewController
to support rotation to landscape orientation. (It's a view controller that shows a chat view, and the landscape mode is easier for typing for some.) I added method - (BOOL) shouldAutorotateToInterfaceOrientation:
to ChildViewController
to declare that it supports landscape orientation, but rotating the device had no effect. From debugging, I found that – willAnimateRotationToInterfaceOrientation:duration:
wasn't being called.
After some searching around online, I've found that a descendent of a UITabBarController
only supports a given orientation if the UITabBarController
itself supports that orientation. And, strangely enough, UITabBarController
only supports an orientation if the view controllers for each of its tabs support rotation. Like tab 1 above, the view controllers for the other three tabs are UINavigationViewController
instances; and, because we must go deeper, each UINavigationViewController
only supports orientation if its child view controller supports the orientation.
So at this point, adding adding - (BOOL) shouldAutorotateToInterfaceOrientation:
to SomeParentViewController
and the children of the other UINavigationController
instances allowed ChildViewController
to rotate. But now SomeParentViewController
and the other three tabs will rotate to landscape, and it looks horrible. I only wanted ChildViewController
to support landscape.
As a latch ditch effort, I created my own UITabBarController
subclass called RotatingUITabBarController
and add a global flag to the ChildViewController
class that lets me know if it has been created and is displayed. The RotatingUITabBarController
overrides only - (BOOL) shouldAutorotateToInterfaceOrientation:
and is implemented as:
if ([ChildViewController isDisplayed]) {
return ((toInterfaceOrientation == UIInterfaceOrientationPortrait) ||
(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft) ||
(toInterfaceOrientation == UIInterfaceOrientationLandscapeRight));
}
return NO;
Now, if I boot the app, switching to SomeParentViewController
or any other tab and rotating the phone does not switch to landscape mode, instead keeping in portrait. So far so good. If I create and display ChildViewController
and rotate the phone, it enters landscape. So far so good. But now if I pop ChildViewController
to reveal SomeOtherParentViewController
, it is also in landscape. And so is SomeParentViewController
and every other tab that I switch to.
I'm out of tricks now. Any advice would be much appreciated, thanks!
Upvotes: 0
Views: 454
Reputation: 124997
Perhaps the best model for the kind of behavior you seem to want is the YouTube app. Most the interface is portrait-only, but the view that plays videos works in either portrait or landscape.
If you look at that app, you'll notice that the whole tabbed part of the UI is actually a modal view controller. When you launch the app, the tab bar controller is immediately presented modally. The only time you leave that modal tab bar controller is when you play a video -- you'll notice that the whole tabbed interface slides down to reveal the video view. When the video ends, the tab bar controller is again presented modally.
This is an inversion of the "normal" approach, where you use a modal view controller only briefly, but it works very well in the YouTube app. It may or may not work well for you too. The important thing is to make your app predictable and fluid, and make the user feel in control at all times.
Upvotes: 1