4

A minimal illustrative Xcode project for this is available on github.

On my UIWindow, when I add second (and subsequent) UITableView's as subviews, they do not rotate properly, and thus appear sideways. This is only tested in the Simulator. Here's a little code for you:

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    ShellTVC* viewA = [[ShellTVC alloc] initWithTitle:@"View A"];
    ShellTVC* viewB = [[ShellTVC alloc] initWithTitle:@"View B"];

    // The first subview added will rotate to landscape correctly. 
    // Any subsequent subview added will not.

    // You may try this by various commentings and rearranging of these two statements.

    [window addSubview:[viewA tableView]];
    [window addSubview:[viewB tableView]];

    [window makeKeyAndVisible];
}

viewB appears sideways. Comment out the addSubview for viewB, and viewA appears correctly. Do that for viewA only, and viewB appears correctly.

I am not creating these UITableViewControllers via NIBs, though the UIWindow is.

In case you are wondering, ShellTVC is-a UITableViewController, and implements this method:

- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

Also, I have set the UIInterfaceOrientation in the plist file to UIInterfaceOrientationLandscapeLeft.

Probably related -- and unanswered -- SO questions here and here.

Community
  • 1
  • 1
Clay Bridges
  • 11,602
  • 10
  • 68
  • 118
  • Please check out the Landscape FAQ for an answer to your question: http://stackoverflow.com/questions/2953351/iphone-landscape-faq-and-solutions – Johannes Rudolph Jun 02 '10 at 09:10
  • 1
    Alternately, upgrade your phone to iOS 4.x. :\ I only get this errant behavior on 3.x devices. – AndrewS Dec 01 '10 at 17:48

6 Answers6

8

I think I figured out a way -- possibly the right way -- to do this.

  1. Create a "master" UIViewController subclass, which implements shouldAutorotate..., and add this as the only view on your window.
  2. To alternate between viewA or viewB, use the combination of dismissModalViewControllerAnimated: & presentModalViewController:animated: on this master view controller.

Here's some code:

// this doesn't really do much but implement shouldAutorotate...
@interface MasterViewController : UIViewController
@end

@implementation MasterViewController
- (BOOL) shouldAutorotateToInterfaceOrientation(UIInterfaceOrientation)interfaceOrientation {
     return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
@end

@interface MyAppDelegate : NSObject <UIApplicationDelegate> {
    MasterViewController* masterVC;
    UIViewController* activeTVC;
    UIViewController* onDeckTVC;
}
@end

- (void)applicationDidFinishLaunching:(UIApplication *)application {
    UIViewController* masterVC = [[MasterViewController alloc] init];        
    activeTVC = [[ShellTVC alloc] initWithTitle:@"View A"];
    onDeckTVC = [[ShellTVC alloc] initWithTitle:@"View B"];
    [window addSubview:masterView.view];
    [window makeKeyAndVisible];
    [masterVC presentModalViewController:activeTVC animated:NO];
}

// you would call this to toggle between "View A" and "View B"
- (void)toggleTVC {
    UITableViewController *hold = activeTVC;
    activeTVC = onDeckTVC;
    onDeckTVC = hold;
    [masterVC dismissModalViewControllerAnimated:NO];   
    [masterVC presentModalViewController:activeTVC animated:NO];
}

Why does this work?

  1. All orientation changes flow through view controllers, not views.

  2. As far as I can tell, the first view or subview that you add to your window gets some special sauce. If that view has a view controller, the window figures it out.

That is, for the first subview only, you can think of this code:

[window addSubview:masterVC.view];

as doing something like this (not a real method!):

[window addSubview:masterVC.view withViewController:masterVC];

I don't understand any more about it than that. I find the fact that I can do this with the first subview, but not others, supremely perplexing. More info welcomed, and please let me know if this helped you or not.

Clay Bridges
  • 11,602
  • 10
  • 68
  • 118
  • 1
    This problem seems to be resolved in iOS 4.x, as I'm working on an iPad app and all was fine until we discovered we had to support 3.2, and I experienced the same problem. This solution worked great for me. Thanks! – Christopher Pickslay Jan 18 '11 at 21:38
1

Apparently if you add viewB as a child of viewA it will be rotated correctly. This is not a great solution for my project, but it looks like it might be the only workaround.

Ed Anuff
  • 283
  • 2
  • 11
0

Unfortunately your subviews are only asked about what orientations they support when a change in orientation occurs.

So I end up setting the orientation before I push the new view controller on the stack if I know it's changed:

[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationPortrait]; 

Yes, this is an unsupported call.

Epsilon Prime
  • 4,576
  • 5
  • 31
  • 34
  • Tried this as the first line of applicationDidFinishLaunching, did not work. – Clay Bridges Oct 28 '09 at 17:09
  • If you want to control your entire application you can edit your Info.plist file to tell it what your default orientation is. Look for the UIInterfaceOrientation key. – Epsilon Prime Oct 28 '09 at 17:27
  • Thanks, yep, I did that. From the original post "Also, I have set the UIInterfaceOrientation in the plist file to UIInterfaceOrientationLandscapeLeft". – Clay Bridges Oct 28 '09 at 18:24
0

You can use the UIApplication object to force a particular device orientation.

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
Lounges
  • 4,674
  • 5
  • 32
  • 43
  • Tried this as the first line of applicationDidFinishLaunching, did not work. Also tried setting this on the passed UIApplication param, did not work. – Clay Bridges Oct 28 '09 at 17:07
-1

Yes, I believe you have to solve this issue by having multiple XIB. I remember seeing this solution through one of books I read in the past. If not, you have play with Translation and position of object in the view... better have separate XIB.

anthony
  • 1
  • 1
-1

This should work.

- (void)viewDidLoad {
    if (([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeLeft) || 
        ([[UIDevice currentDevice] orientation] == UIDeviceOrientationLandscapeRight)) 

    {
        self.view.frame = CGRectMake(0, 0, 1024, 748);

    } else {
        self.view.frame = CGRectMake(0, 0, 768, 1004);
    }
}
dqatsh
  • 1