Trick preferredInterfaceOrientationForPresentation

2019-02-21 20:32发布

问题:

I am using MSNavigationPaneViewController from here and have rotation sort of working. I've overridden the rotation methods in my root UINavigationController

-(BOOL)shouldAutorotate
{
    return YES;
}
-(NSUInteger)supportedInterfaceOrientations
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    if (appDelegate.topViewController != nil) {
        return [appDelegate.topViewController supportedInterfaceOrientations];
    } else {
        return UIInterfaceOrientationMaskPortrait;
    }
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
    if (appDelegate.topViewController != nil) {
        return [appDelegate.topViewController preferredInterfaceOrientationForPresentation];
    } else {
        return UIInterfaceOrientationPortrait;
    }
}

which I push the MSNavigationPaneViewController with using presentViewController: animated:completion: and I have rotation working so certain views can have different orientations. The problem is, each view that has a different orientation needs the user to tilt the phone to change the orientation at which point it locks on the correct orientation. I've done tons of reading to get this working and it seems I need preferredInterfaceOrientationForPresentation to fire before each view is loaded, but it's not firing. I think it's not firing because the MSNavigationPaneViewController isn't changing view controllers using presentViewController. This is the code used by MSNavigationPaneViewController to change the view

- (void)setPaneViewController:(UIViewController *)paneViewController
{
    if (_paneViewController == nil) {

        paneViewController.view.frame = _paneView.bounds;
        _paneViewController = paneViewController;
        [self addChildViewController:_paneViewController];
        [_paneView addSubview:_paneViewController.view];
        [_paneViewController didMoveToParentViewController:self];

    } else if (_paneViewController != paneViewController) {

        paneViewController.view.frame = _paneView.bounds;
        [_paneViewController willMoveToParentViewController:nil];
        [self addChildViewController:paneViewController];

        void(^transitionCompletion)(BOOL finished) = ^(BOOL finished) {
            [_paneViewController removeFromParentViewController];
            [paneViewController didMoveToParentViewController:self];
            _paneViewController = paneViewController;
        };

        [self transitionFromViewController:_paneViewController
                          toViewController:paneViewController
                                  duration:0
                                   options:UIViewAnimationOptionTransitionNone
                                animations:nil
                                completion:transitionCompletion];
    }
}

which looks like it's just switching the viewController and therefor not calling preferredInterfaceOrientationForPresentation

Is there any way to force preferredInterfaceOrientationForPresentation to be called, or to trick it into be called maybe by a hidden view?

Thanks

EDIT ----

I totally understand how the new rotation system works in iOS6 and that it's down to the root to manage it. However preferredInterfaceOrientationForPresentation only seems to be called if the next view is being presented with one of the correct methods. Not if the window is just switched. So I do actually need a way to trick this to be called.

回答1:

You can trick the window into re-valuating its supported interface orientations by resetting its rootViewController.

UIApplication *app = [UIApplication sharedApplication];
UIWindow *window = [[app windows] objectAtIndex:0];
UIViewController *root = window.rootViewController;
window.rootViewController = nil;
window.rootViewController = root;

You'd need to make sure that when this code executes, -supportedInterfaceOrientations of the root view controller returns the proper mask (corresponding to how you want to force the orientation).

Be aware, this hack can cause a quick flash on the screen and glitch any ongoing animations.



回答2:

preferredInterfaceOrientationForPresentation will not be called on controllers within a UINavigationController.

You are going to have to subclass UINavigationController and then implement this feature yourself. You'd simply want to delegated to topViewController.

For reference check out: http://code.shabz.co/post/32051014482/ios-6-supportedorientations-with-uinavigationcontroller

I also found this implementation of a UINavigationController subclass: https://gist.github.com/3842178