iPhone: In landscape-only, after first addSubview, UITableViewController doesn't rotate properly
Asked Answered
A

6

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.

Acetum answered 27/10, 2009 at 16:38 Comment(2)
Please check out the Landscape FAQ for an answer to your question: #2953851Cambrian
Alternately, upgrade your phone to iOS 4.x. :\ I only get this errant behavior on 3.x devices.Toxicogenic
A
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.

Acetum answered 11/4, 2010 at 2:36 Comment(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!Hemihydrate
P
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.

Papeete answered 10/4, 2010 at 2:1 Comment(0)
J
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.

Jowers answered 27/10, 2009 at 17:49 Comment(3)
Tried this as the first line of applicationDidFinishLaunching, did not work.Acetum
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.Jowers
Thanks, yep, I did that. From the original post "Also, I have set the UIInterfaceOrientation in the plist file to UIInterfaceOrientationLandscapeLeft".Acetum
J
0

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

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];
Jimmy answered 27/10, 2009 at 18:53 Comment(1)
Tried this as the first line of applicationDidFinishLaunching, did not work. Also tried setting this on the passed UIApplication param, did not work.Acetum
B
-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.

Bruell answered 27/8, 2010 at 15:10 Comment(0)
A
-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);
    }
}
Alibi answered 10/12, 2010 at 8:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.