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

耗尽温柔 提交于 2019-11-30 15:48:52

问题


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.


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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

[[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];



回答5:


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.




回答6:


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);
    }
}


来源:https://stackoverflow.com/questions/1632117/iphone-in-landscape-only-after-first-addsubview-uitableviewcontroller-doesnt

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!