0

I've subClassed my NavigationController and added this code:

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft |UIInterfaceOrientationMaskPortrait;
} 
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationLandscapeLeft;
}

I have 2 view controllers. How can I force landscape mode on one and portrait mode on another without the ability to rotate? (all ordinations are enabled in the plist)

Segev
  • 19,035
  • 12
  • 80
  • 152

3 Answers3

0

Assuming you're using iOS6, change your custom navigation controller to have this (this solution only seems to work for modal or full screen presentations):

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

and

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

and then in the controller that you want to have Landscape add

    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;
    }
    - (BOOL)shouldAutorotate
    {
        return YES;
    }

and in the other

    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskPortrait;
    }

    - (BOOL)shouldAutorotate
    {
        return YES;
    }
Mike M
  • 4,358
  • 1
  • 28
  • 48
  • The first ViewController will start in landscape mode but when i'll push to the next VIewController it won't change to portrait. For some reason only the first ViewController is effected by this – Segev Apr 30 '13 at 20:10
  • if you physically orient the second VC in portrait, will it a) go to portrait and b) stay in portrait when you switch back to landscape? – Mike M Apr 30 '13 at 20:13
  • it will switch to portrait and will stay on portrait – Segev Apr 30 '13 at 20:15
  • I just changed the shouldAutorotate to return NO for the VC's. Not sure if that will do the trick. – Mike M Apr 30 '13 at 20:16
  • If I add this: `UIViewController *portraitViewController = [[UIViewController alloc] init]; UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController]; [self.navigationController presentViewController:nc animated:NO completion:nil]; [self.navigationController dismissViewControllerAnimated:NO completion:nil];` I get the right ordination but it feels like a hack for me so i'm trying to find a better solution – Segev Apr 30 '13 at 20:31
  • I'm also experimenting with preferredInterfaceOrientationForPresentation which works, but somehow I'm losing the nav bar. If/when I figure that out I'll update my answer – Mike M Apr 30 '13 at 20:38
  • It looks like you can make it work if the VC is presented modally or full screen. If you have to have the nav bar, then I haven't found a way to make it work. – Mike M Apr 30 '13 at 21:06
  • Thanks you for your help. I've found a better solution for this with out losing the nav bar. I'll post it here as an answer in a few. – Segev May 01 '13 at 10:49
0

I am considering rotation for iOS 6.0 and above only. Creating category for UINaviagtionController can be a good approach here. So follow these steps

Step 1. Put this code in your AppDelegate.m

    - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
    {
        return UIInterfaceOrientationMaskAll;
    }

Step 2. Create a category for UINaviagtionController

Orientation.h

    #import <Foundation/Foundation.h>

    @interface UINavigationController (Orientation)

    @end

Orientation.m

    #import "Orientation.h"

    @implementation UINavigationController (Orientation)

    - (BOOL)shouldAutorotate {
       if (self.topViewController != nil)
            return [self.topViewController shouldAutorotate];
       else
            return [super shouldAutorotate];
     }

    - (NSUInteger)supportedInterfaceOrientations {
        if (self.topViewController != nil)
            return [self.topViewController supportedInterfaceOrientations];
        else
            return [super supportedInterfaceOrientations];
    }

    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
        if (self.topViewController != nil)
            return [self.topViewController preferredInterfaceOrientationForPresentation];
        else
            return [super preferredInterfaceOrientationForPresentation];
    }

Step 3. Now create a UIViewController class that forces initial orientation. For Portrait

PortraitVC.h

    #import <UIKit/UIKit.h>

    @interface PortraitVC : ViewController

    @end

PortraitVC.m

    - (BOOL)shouldAutorotate
    {
        return NO;
    }

    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskPortrait;
    }
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
       return UIInterfaceOrientationPortrait;
    }

Similarly For Landscape

LandscapeVC.h

    #import <UIKit/UIKit.h>

    @interface LandscapeVC : ViewController

    @end

LandscapeVC.m

    - (BOOL)shouldAutorotate
    {
        return NO;
    }

    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskLandscape;
    }
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
       return UIInterfaceOrientationLandscapeLeft;
    }

Step 4. Now your original ViewController which you want to force in Portrait Mode only and without having rotation, write this code in your viewDidLoad

    PortraitVC *c = [[PortraitVC alloc] init];
    [self presentViewController:c animated:NO completion:NULL];
    [self dismissViewControllerAnimated:NO completion:NULL];

And set the orientations like this

    - (BOOL)shouldAutorotate
    {
        return NO;
    }

    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskPortrait;
    }
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
       return UIInterfaceOrientationPortrait;
    }

If you want to force your original ViewController in Landscape Mode only and without having rotation, write this code in your viewDidLoad

    LandscapeVC *c = [[LandscapeVC alloc] init];
    [self presentViewController:c animated:NO completion:NULL];
    [self dismissViewControllerAnimated:NO completion:NULL];

And set the orientations like this

    - (BOOL)shouldAutorotate
    {
        return NO;
    }

    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskLandscape;
    }
    - (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
    {
       return UIInterfaceOrientationLandscapeLeft;
    }

I did this because "preferredInterfaceOrientationForPresentation" is called only when we use presentViewController or presentModalViewController. And to set initial orientation "preferredInterfaceOrientationForPresentation" must be called.

Hope this helps.

Teena nath Paul
  • 2,219
  • 23
  • 28
0

So after a lot of trails and error I've found a solution I can work with.

In your AppDelegate:

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
    NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

    if(self.window.rootViewController){
        UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
        orientations = [presentedViewController supportedInterfaceOrientations];
    }

    return orientations;
}

This will give the control of the orientations to the root view controller.

in your DataManager.h (Or any other singleton you are using.. can be done with NSUserDefaults too.

@property (nonatomic, strong) NSString *currentView;

In your ViewController.m (root):

-(NSUInteger)supportedInterfaceOrientations
{

    if([[DataManager sharedDataManager].currentView isEqualToString:@"Trailer"])
    {
        return UIInterfaceOrientationMaskLandscapeRight;
    }
    else if([[DataManager sharedDataManager].currentView isEqualToString:@"Menu"])
    {
        return UIInterfaceOrientationMaskPortrait;
    }

    return UIInterfaceOrientationMaskPortrait;
}

From the root ViewController you'll have access to all the orientations of all the ViewControlles in your app. Very useful if you want to limit one ViewController to landscape and the other just to portrait. The only thing you'll need to add to each ViewController is inside ViewWillAppear the name you want to give to the ViewController like so:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    [DataManager sharedDataManager].currentView = @"Menu";
}

With this solution you won't get the annoying warnings about switching between views to rapidly like you get with the present \ dissmis view solution for forcing rotation. Maybe there's a way to identify the ViewController in a better way, I'd love to hear how. I would also love to hear if you find any problems with this solution. Thanks

Segev
  • 19,035
  • 12
  • 80
  • 152
  • The problem is that this doesn't work for me (and neither do similar solutions). Here's the simplest possible case: navigation controller, its root view controller (ViewController), and a second view controller (ViewController2) to be pushed and popped on the nav stack. I'd like ViewController's view to appear only in portrait and and ViewController2's view to appear only in landscape. I can't achieve that with your solution (as I understand it). If you could post a working example to github, though, that would be great! – matt May 01 '13 at 16:16
  • I have made a movie of the sort of thing I'm looking for: http://youtu.be/O76d6FhPXlE But that is accomplished with a presented view; there are actually two different navigation controllers, one of which is presented modally. I can't find any way to do it with *just* one navigation controller. – matt May 04 '13 at 22:03
  • Hey matt, just saw your comment. You are right, the solution above only handles presented view. Pushed view controllers won't rotate. What do you mean 2 navigation controllers? I'm only uses one with the example above and it's working fine. (the nv controller is not even subclassed) – Segev May 04 '13 at 22:16
  • Yes, see now my second answer here: http://stackoverflow.com/a/16379515/341994 If there is a better way to achieve this, I'd love to know about it! As I say, if you could post a working example to github, that would be great. Meanwhile, though, I think my solution is a pretty fair compromise. – matt May 04 '13 at 22:26
  • I'll try to explain my self a bit better before i'm posting it.I was wrong when I thought you can push view controllers. My solution uses presented view controls only, I guess I can use a custom segue to mimic the "push" animation. Looks pretty smooth on my end with no blinking like in your movie. Do you still want me to post it? – Segev May 04 '13 at 22:36
  • I guess I no longer understand your answer above. If you are just using presented view controllers, why do you need all the foodly-doodly with `application:supportedInterfaceOrientationsForWindow:` and your DataManager? With a presented view controller, forcing rotation just works automatically: each view controller's `supportedInterfaceOrientations` is obeyed. – matt May 04 '13 at 22:53