7

I am trying to follow a previous question in allowing a navigation controller view controllers in having different orientation rules. Previous Question

So for example, I have two view controllers the first is a Welcome the second Home. I would like the first view controller to only be Potrait and the second (Home) to allow both Port/Landscape.

I am not sure I quite understand in full how to complete this. Once I do, I intend to create a seperate project explaining how to do this and add to Github/share on the question for future reference.

In this particular project I am using a side view controller github project. PPRevealSideViewController.

My app Delegate is the following:

// Then we setup the reveal side view controller with the root view controller as the navigation controller
welcomeViewController = [[MESWelcomeViewController alloc] init];
UINavigationController *navController = [[MESNavViewControllerSubClass alloc] initWithRootViewController:welcomeViewController];


self.revealSideViewController = [[PPRevealSideViewController alloc] initWithRootViewController:navController];
[self.revealSideViewController setDirectionsToShowBounce:PPRevealSideDirectionNone];
[self.revealSideViewController setPanInteractionsWhenClosed:PPRevealSideInteractionContentView | PPRevealSideInteractionNavigationBar];

//self.window.rootViewController = welcomeViewController;
self.window.rootViewController = self.revealSideViewController;
[self.window makeKeyAndVisible];

From the above you can see I have subclassed the Navigation Controller as MESNavViewController. This is my head for this file:

@interface MESNavViewControllerSubClass : UINavigationController {
    BOOL setLandscapeOK;
}

Imp file for MESNavViewController:

-(void)viewDidLoad {
    NSLog(@"subclass called");
}

- (BOOL)shouldAutorotate
{
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if (self->setLandscapeOK) {
        // for iPhone, you could also return UIInterfaceOrientationMaskAllButUpsideDown
        return UIInterfaceOrientationMaskAll;
    }
    return UIInterfaceOrientationMaskPortrait;
}

In my first (Welcome) View controller I have the following:

-(void)viewWillAppear {
    BOOL setLandscapeOK = NO;
}
- (NSInteger)supportedInterfaceOrientations {
    // Restriction for the welcome page to only allow potrait orientation
    return UIInterfaceOrientationMaskPortrait;
}

In my second (Home) View controller I have only the following:

-(void)viewWillAppear {
    BOOL setLandscapeOK = YES;
}

What I am seeing is both view controllers within the nav allow either orientation. I am not sure I quite understand it correctly. Hopefully I have provided enough information.

EDIT ----- I have updated the PPRevealSidePanel sub class which is the very top level controller. This then holds the nav controller, which in turn holds the view controller. The orientation should be decided by the view controller displayed.

PPRevealSidePanel Sub class - enter image description here

Secondly I receive an error trying to update the setter setLandscapeOK for this sub class, on the actual view controller. Login View controller - enter image description here

Community
  • 1
  • 1
StuartM
  • 6,743
  • 18
  • 84
  • 160
  • What are you trying to accomplish? What is the question? – Simon Goldeen Feb 07 '13 at 20:36
  • This is within the question "So for example, I have two view controllers the first is a Welcome the second Home. I would like the first view controller to only be Potrait and the second (Home) to allow both Port/Landscape." – StuartM Feb 07 '13 at 21:22

3 Answers3

2

Can you check the below thread which talks about handling orientation with nav controllers

NavController ShouldAutorotate

-anoop

Community
  • 1
  • 1
anoop4real
  • 7,598
  • 4
  • 53
  • 56
  • This is what I have tried to implement but do not understand fully how this should work. – StuartM Feb 19 '13 at 18:36
  • Okay,I have done a sample for you, not sure this is what you are looking for....in the sample the View1 will autorotate and View2 will not autorotate under the same nav controller find the code here http://www.sendspace.com/file/b5jmjv – anoop4real Feb 20 '13 at 17:13
  • I have downloaded it, but in your example both view controllers can go landscape and portrait. I am looking for one fixed only portrait and one both? – StuartM Feb 20 '13 at 21:24
  • 1
    Okay, you need to handle supportedInterfaceOrientations, preferredInterfaceOrientationForPresentation also. I have modified the code, since I dont have iOS6 sdk at home, I couldnt test it..but i think this should work. There may be small errors but you shoud be able to tweak. In the new code the view1 will load in portrait since i set preffered orientation as portrait and view2 will load in any orientation, shouldrotate code remains same. http://www.sendspace.com/file/f2z81z – anoop4real Feb 21 '13 at 14:18
  • You are correct, I receive an error - No visible @interface for NSArray declares the selector topViewController. As I do not know enough about what you are trying to explain I am lost to be honest... – StuartM Feb 21 '13 at 14:51
  • Spoke to soon, I updated these lines to [self.navigationController topViewController... which resolved the issue. I should be able to work it out from here, thanks – StuartM Feb 21 '13 at 14:53
  • I cannot award the bounty but as you are the only accepted answer it will automatically award to you. – StuartM Feb 21 '13 at 14:54
0

Is your viewWillAppear method being called? The actual method is - (void)viewWillAppear:(BOOL)animated.

Aside from that, the issue is that supportedInterfaceOrientations is called before viewWillAppear. Try setting your BOOL flag in your initWithNibName method.

EDIT:

something like this:

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        self.setLandscapeOK = YES;
    }
    return self;
}

EDIT 2:

I just noticed you're re-declaring setLandscapeOK as a new variable in viewWillAppear. This is hiding your superclass's instance of that variable. Try using self.setLandscapeOK instead of BOOL setLandscapeOK

EDIT 3:

Since you aren't subclassing your main nav controller, the above stuff wont work. You'll need an explicit way of notifying your navigation controller that it's subview doesnt want it to support certain orientations. When you push the viewcontroller that is portrait only, setLandscapeOK should be set to NO.

Chris C
  • 3,221
  • 1
  • 27
  • 31
  • I have updated the method to no avail. Also added an NSLog to ensure it is called... and it is. I have moved the setLandscapeOK = NO; (for the first Welcome view controller) into the ViewDidLoad instead and still no difference. I cannot move into *withNibName as I am not using NIBs – StuartM Feb 07 '13 at 22:57
  • I updated my post to something you can try adding. Whether you're using NIBs or not, that method still is called. – Chris C Feb 07 '13 at 23:01
  • 1. If I set the above EDIT, I have an error Property setLanscapeOKnot found... in MESWelcomeViewController. This is because I subclassed the nav controller to add this variable not view controller? 2. I also get an error updating to self.setLandscapeOK in the nav controller sub class too - Property setLandscapeOK not found on MESNavViewControllerSubClass did you mean to access the instance variable? – StuartM Feb 07 '13 at 23:11
  • OK I see what you're doing now. Your Nav controller is your root viewcontroller, and you have two separate view controllers that you push onto the nav controller. iOS handles rotation based on the highest level root view controller that takes up the whole screen, in this case it's your nav controller. I'll edit my post again – Chris C Feb 07 '13 at 23:13
  • Not sure I understand the edit or actual issue here enough. I have tried to sub class the PPRevealSidePanel which is the top level too and added the information previously in Nav Controller subclass from the question information above, but still the same issue not working – StuartM Feb 07 '13 at 23:22
  • Rotation rules only apply to the highest level view that takes up the whole screen. So if you have a navigation controller that pushes other view controllers onto itself, that navigation controller's rotation rules will be the only ones the app checks. This means your bool flag has to be in the navigation controller class, and you need to switch it based on which view you have pushed – Chris C Feb 07 '13 at 23:24
  • Ok. So in this case I have a PPRevealSideViewController as the top level, then a nav Controller in that, and then the relevant View currently pushed. I need the current view to decide wether the whole screen (all three views, view/nav/revealside) should rotate. I am not sure how to implement this though? – StuartM Feb 07 '13 at 23:30
  • I have also tried to update the MESSidePanelViewControllerSubClass with the nav controller code included in the question. Then updated the Welcome view controller initWithNibName to have '[(MESSidePanelViewControllerSubClass*)[self navigationController] setLandscapeOK:YES];' but I receive an error - no visible interface for MESSidePanelViewControllerSubClass declares the selector setLandscapeOK? How do I make this selector? – StuartM Feb 07 '13 at 23:38
0

What goes wrong in your case is that you're overriding -supportedInterfaceOrientations in that UINavigationController subclass, so that method never gets passed to its child ViewControllers. Also you're declaring a new setLandscapeOK BOOL in viewWillAppear, not changing the global one. What is weird is that based on the code you've posted your app should be stuck in portrait, not allow all orientations, since you never seem to set the setLandscapeOK boolean to YES in the UINavigationController subclass.

But you seem to make things a lot more complicated than they should be. You shouldn't need that setLandscapeOK boolean and you shouldn't need to subclass UINavigationController or the PPRevealSideViewController just for the rotation issue. Both PPRevealSideViewController and UINavigationController are container ViewControllers, aka parent ViewControllers that contain child ViewControllers. By default when an orientation callback is called on the parent ViewController, it will call and return the same method of the child ViewController.

When -shouldAutoRotate, -supportedInterfaceOrientations or -shouldAutoRotateToInterfaceOrientation is called on the PPRevealSideViewController, it will call the same methods on its rootViewController, in your case a UINavigationController. The UINavigationController is also a container ViewController and will call the same method on the currently visible ViewController, in your case either the WelcomeViewController or the HomeViewController.

So, all you need to do is override -supportedInterfaceOrientations and -shouldAutoRotateToInterfaceOrientation in the WelcomeViewController (return portrait only) and the HomeViewController (return all). Don't override these methods in MESNavViewController, you shouldn't even need this subclass. You don't need to do anything else. You can remove that setLandscapeOK boolean in all of your ViewControllers as well.

David
  • 1,152
  • 8
  • 13
  • Thanks for your response. I have updated the code and removed the subclass for Nav/revealside commenting out all of the above. I have added supportInterfaceOrientations to both the Home and Welcome views but the shouldAutoRorateToInterfaceOrientation is depreciated... Just having the supportInterfaceOrientations in both view controllers does not work. They both always allow port/landscape now, any other thoughts? – StuartM Feb 14 '13 at 08:11
  • shouldAutoRorateToInterfaceOrientation is deprecated in iOS6, but you still need to implement it if you also support iOS5. If you're testing on iOS5, try implementing that first. Try setting breakpoints in the supportedInterfaceOrientations and shouldAutorotateToInterfaceOrientation methods and look at the call stack to see when and by which parent ViewController these methods are called. – David Feb 14 '13 at 08:50
  • You are correct but at the moment I am building for iphone 6.0. I have implemented both methods in my Welcome/Home controllers but both allow either orientation. I have looked here:-https://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/RespondingtoDeviceOrientationChanges/RespondingtoDeviceOrientationChanges.html#//apple_ref/doc/uid/TP40007457-CH7-SW5 and this seems to be setup correctly, but it must be overriding somewhere. When testing in ios6.0 simulator I see the supportedInterfaceOrientations is called but no difference made. – StuartM Feb 15 '13 at 08:12
  • Any other thoughts @Snppls? – StuartM Feb 19 '13 at 18:36