views:

2306

answers:

7

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.

A: 

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
Tried this as the first line of applicationDidFinishLaunching, did not work.
Clay Bridges
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
Thanks, yep, I did that. From the original post "Also, I have set the UIInterfaceOrientation in the plist file to UIInterfaceOrientationLandscapeLeft".
Clay Bridges
A: 

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

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
Lounges
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
A: 

Did you ever find an answer for this? I have the same issue. :-( March 19 2010.

KingAndrew
No, not yet. There might be a way around it by using interface builder, but at present I do not have a fix. I will post to this space the minute I do.
Clay Bridges
A: 

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
+3  A: 

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
Thanks, this solved my problem!
confusedKid
A: 

See http://www.pushplay.net/blog_detail.php?id=27 It is a framework which should work with the accepted solution.

David Lawson
A: 

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