Allow change of orientation to landscape for only one tab in UITabViewController

915 views Asked by At

Is this possible? How might I accomplish this?

2

There are 2 answers

2
Nate On BEST ANSWER

Not possible according to Apple Docs.

The word possible may need an asterisk by it. It certainly looks like Apple didn't envision (or want) you doing this. But, depending on what your requirements are, there may be a workaround.

Disclaimer: this is kind of a hack. I'm not claiming this to be a good UI, just trying to show Eli what's possible.

I built an example, starting with the Xcode template for building a Tabbed Application. It has two view controllers: FirstViewController and SecondViewController. I decided to make FirstViewController the landscape-only view. In Interface Builder (Xcode UI design mode), I set the orientation of the FirstViewController's view to landscape, and made its size 480 wide by 251 high (I'm assuming iPhone/iPod here).

Solution

Now, what seems to be necessary is to have all the tab bar's view controllers claim to support autorotation to portrait and landscape. For example:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

So, both my view controllers have that same code. However, what I do in FirstViewController is to also override willAnimateToInterfaceOrientation:duration: and essentially undo what the UIViewController infrastructure does, just for this one landscape-only view controller.

FirstViewController.m:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
    [super willAnimateRotationToInterfaceOrientation:interfaceOrientation duration:duration];

    CGAffineTransform viewRotation;
    CGRect frame;

    if (UIInterfaceOrientationIsLandscape(interfaceOrientation)) {
        viewRotation = CGAffineTransformIdentity;
        // TODO: change to dynamically account for status bar and tab bar height
        frame = CGRectMake(0, 0, 480, 320 - 20 - 49);        
    } else {
        viewRotation = CGAffineTransformMakeRotation(M_PI_2);
        // TODO: change to dynamically account for status bar and tab bar height
        frame = CGRectMake(0, 0, 320, 480 - 20 - 49);        
    }

    // undo the rotation that UIViewController wants to do, for this view heirarchy
    [UIView beginAnimations:@"unrotation" context: NULL];
    [UIView setAnimationDuration: duration];

    self.view.transform = viewRotation;
    self.view.frame = frame;

    [UIView commitAnimations];
}

What you get with this is that the tab bar will always rotate with the device. That's probably a requirement, to get your dual orientation views (e.g. SecondViewController) to do autorotation. But, the actual view content of FirstViewController now does not rotate. It stays in landscape orientation, no matter how the user turns the device. So, maybe that's partially good enough for you?

Also of note:

1) I changed the app's info plist file to set the initial orientation to landscape (since my FirstViewController was the landscape one):

<key>UISupportedInterfaceOrientations</key>
<array>
    <string>UIInterfaceOrientationPortrait</string>
    <string>UIInterfaceOrientationLandscapeLeft</string>        
    <string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>

2) In FirstViewController.xib, I set the main/parent UIView to not Autoresize Subviews. Depending on your view hierarchy, you may want to change this property in other child views, too. You can experiment with that setting.

Now, the available size for your landscape view does change a little bit, as the status bar and tab bar are rotated. So, you may need to adjust your layout a little bit. But, basically, you will still get a wide view for showing landscape content, no matter how the user holds their device.

Results

Watch Youtube demo of running app

0
Andy Obusek On

Not possible according to Apple Docs. All UIViewControllers must support the same orientations for any to be rotatable.

See this document (scroll down to the section titled "Tab Bar Controllers and Rotation": http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/TabBarControllers.html#//apple_ref/doc/uid/TP40011313-CH3-SW1