简体   繁体   中英

In iOS6, trouble forcing ViewController to certain interfaceOrientation when pushed on stack

I have the following view controller set up:

viewController1 is able rotate freely to any orientation except portrait upside down.

viewController2 gets pushed on top of viewController1, and I'd like for it to be the same orientation viewController1 is and I'd like for it not to be able to rotate.

viewController3 gets pushed on top of viewController2. I'd like for viewController3 to be in portrait mode.

I'm having a lot of issues trying to accomplish this in iOS6 (haven't tried yet in iOS5). First off, I have already created my own Navigation Controller and put the following in it:

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [self.topViewController preferredInterfaceOrientationForPresentation];
}

- (NSUInteger)supportedInterfaceOrientations
{
    return [self.topViewController supportedInterfaceOrientations];
}

- (BOOL) shouldAutorotate
{
    return [self.topViewController shouldAutorotate];
}

I've tried a lot of different combinations of these things to know avail. Mainly where I'm struggling is forcing vc3 to be presented as portrait if vc2 is in landscape. Any help would be appreciated.

What you're trying to do here is fighting the framework. What you're describing is simply not how a navigation controller architecture works in iOS 6. If you want to show a view controller's view and force rotation, use a presented view controller. That's the only time preferredInterfaceOrientationForPresentation is meaningful, and your view controller's supportedInterfaceOrientations will actually be consulted because, being presented, it will be at the root of the interface.

I have explained in a different answer that it is not supported, in iOS 6, to force rotation when pushing a new view controller on to a navigation controller. You can structure rules about compensatory rotation (ie what should happen if the user rotates the device ), but you can't force the interface to rotate. The only situation in which iOS 6 is happy to let you force rotation is when presenting or dismissing a view controller ( presentViewController:animated: and dismissViewControllerAnimated: ).

However, it is possible to use a presented view controller in such a way that it kind of looks like you're pushing onto the navigation controller. I've made a movie showing what I mean:

http://youtu.be/O76d6FhPXlE

Now, that's not totally perfect by any means. There is no rotation animation of the status bar, and there is a kind of black "blink" between the two views - which is intentional, because it's there to cover up what is really going. What's really going on is that there are really two difference navigation controllers and three view controllers, as shown in this screen shot of the storyboard.

在此处输入图片说明

What we have is:

  • a nav controller subclass set to portrait orientation, and its root view controller

  • a second nav controller subclass set to landscape orientation, and its root view controller, which is black and functions as an intermediary

  • a third view controller to be pushed onto the second nav controller's stack

When the user asks to go "forward" from the first view controller, we present the second navigation controller, thus seeing the black view controller momentarily, but then we immediately push the third view controller. So we get forced rotation, along with a kind of black flash and a push animation. When the user taps the Back button in the third view controller, we reverse the process.

All the transitional code is in the black view controller (ViewControllerIntermediary). I've tried to tweak it to give the most satisfying animation I can:

@implementation ViewControllerIntermediary {
    BOOL _comingBack;
}

- (void) viewDidLoad {
    [super viewDidLoad];
    self.navigationController.delegate = self;
}

-(void)navigationController:(UINavigationController *)nc 
        willShowViewController:(UIViewController *)vc 
        animated:(BOOL)anim {
    if (self == vc)
        [nc setNavigationBarHidden:YES animated:_comingBack];
    else
        [nc setNavigationBarHidden:NO animated:YES];
}

-(void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (!_comingBack) {
        [self performSegueWithIdentifier:@"pushme" sender:self];
        _comingBack = YES;
    }
    else
        [self.navigationController dismissViewControllerAnimated:YES 
            completion:nil];
}
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
    SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;

    if (secondController.isPresented)
        return UIInterfaceOrientationMaskAll;
    else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}

And for Swift

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {

    if self.window?.rootViewController?.presentedViewController? is SecondViewController {

        let secondController = self.window!.rootViewController.presentedViewController as SecondViewController

        if secondController.isPresented {
            return Int(UIInterfaceOrientationMask.All.toRaw());
        } else {
            return Int(UIInterfaceOrientationMask.Portrait.toRaw());
        }
    } else {
        return Int(UIInterfaceOrientationMask.Portrait.toRaw());
    }

}

For more details check this link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM