Trick preferredInterfaceOrientationForPresentation to fire on viewController change
Asked Answered
W

2

7

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.

Wyon answered 18/12, 2012 at 14:12 Comment(0)
P
9

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.

Peisch answered 21/12, 2012 at 21:21 Comment(3)
Thanks. This did make the rotation change :-) The only problem with this solution is that any modal views currently displayed, end up hidden. Possibly behind the rootView. I have managed a hack work around though to re-present the current modal view after switching rootViewController. ThanksWyon
This doesn't seem to work in iOS 7, for me at least, in a parent/child viewController setup.Doud
Works on iOS 7. Like a charm.Theatrician
D
6

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

Dre answered 19/12, 2012 at 1:52 Comment(2)
Hi thanks. I have already done this to get the shouldRotate working. The problem is preferredInterfaceOrientation isn't called even in the nav controller unless you 'present' the next view and not just switch it out.Wyon
Hi all, I'm new to iOS development, can some one guide me how to add this sub class.Berzelius

© 2022 - 2024 — McMap. All rights reserved.