1

In direct reference to this question:

How to stop rotation of ABPersonViewController & ABNewPersonViewController in Landscape mode in iphone

How can I prevent this screen from rotating in iOS 6 when I am not the one pushing the view controller? Scenario being I create a new contact, and the user then presses either the 'Create new contact' or 'Add to existing contact' buttons. The screen produced is the ABNewPersonViewController but because I do not have direct access to the rotation methods, I am unable to prevent it from rotating.

Screenshot:

enter image description here

The above image is taken from a subclass of the ABUnknownPersonViewController, in this subclass the only functionality I have implemented is to override the rotation methods as follows:

- (BOOL)shouldAutorotate
{
    return NO;
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    if(toInterfaceOrientation == UIInterfaceOrientationPortrait)
        return YES;

    return NO;
}

However, the issue is, I cannot then subclass the ABNewPersonViewController screen that is pushed when one of the buttons in the above image is pressed to override the rotation on iOS 6. Any ideas on how I can legitimately get access to these buttons OR override the rotation on the screen that is pushed to prevent it from doing so?

UPDATE 1:

I attempted to create a category on the ABNewPersonViewController and ABUnknownPersonViewController that overrode the rotation methods (not ideal, I know) and then globally imported, but this did not work. Other than this, I am completely stuck for ideas on how to override this behaviour. Any suggestions?

UPDATE 2:

Is it possible to gain a reference to the buttons in that UITableView and override the methods they call? Or is this in violation of Apple terms by accessing private APIs? Trying to investigate this approach so far and not really getting anywhere.

Community
  • 1
  • 1
Tim
  • 8,932
  • 4
  • 43
  • 64
  • In iOS 6 what orientations views are allowed to rotate to is controlled by the presenting view controller, unless the view presented is full-screen (modal). Can you elaborate on your view/navigation controller hierarchy? Knowing what view controllers you have, and what is presenting what, I can help you figure out where to use the orientation methods to lock orientation changes. – Andrew Theis Apr 23 '13 at 01:22
  • The screenshot above is the top of the View Controller stack, it has been pushed onto the stack and it is a subclass of the ABUnknownPersonViewController, within this subclass I override the rotation methods to prevent it from rotating. When Create or Add Existing button is pressed, an ABNewPersonViewController is presented from the ABUnknownPersonViewController subclass, but I do not have access to this code, hope this explains it. – Tim Apr 23 '13 at 08:58
  • Ah ok, see my answer below. – Andrew Theis Apr 23 '13 at 18:33

3 Answers3

6

On iOS 6, rotation handling has changed. There are two options to prevent the rotation:

  1. You can set your whole app to only support portrait orientation in your Info.plist.
  2. You can override a method in your application delegate:

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

    As that method is called on your delegate whenever the orientation changes or a new view controller is pushed, you can even use it to temporarily disable landscape display:

    // In AppDelegate.h:
    @property (nonatomic) BOOL portraitOnly;
    
    // In AppDelegate.m:
    - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
    {
        return _portraitOnly ? UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAllButUpsideDown;
    }
    
    // to switch to portrait only:
    ((AppDelegate *)[UIApplication sharedApplication].delegate).portraitOnly = YES;
    
    // to switch back to allowing landscape orientations as well:
    ((AppDelegate *)[UIApplication sharedApplication].delegate).portraitOnly = NO;
    

Both methods are perfectly acceptable for App Store submission, as these only use published and documented behavior.

Tammo Freese
  • 10,514
  • 2
  • 35
  • 44
  • This will prevent a particular view controller on the app that does need to rotate to landscape unfortunately! – Tim Apr 23 '13 at 18:47
  • It shouldn't if you use the solution with `portraitOnly`! Set `portraitOnly` to `YES` before presenting the person view controller, and set it to `NO` before dismissing the person view controller. Then it should work fine. If you still have problems, let me know, I have a working example, and can add more code if you like. – Tammo Freese Apr 23 '13 at 19:03
  • Thanks! I think this will do great, feels a little bit like a hack. But seems like the only solution. – Tim Apr 23 '13 at 20:20
1

Going off of Tammo Freese answer. I assume the view that needs to be allow landscape is lower in the view stack than your custom ABUnknownPersonViewController. If so in your ABUnknownPersonViewController subclass over add this

- (void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    ((AppDelegate *)[UIApplication sharedApplication].delegate).portraitOnly = YES;
}
- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:(BOOL)animated];    
    ((AppDelegate *)[UIApplication sharedApplication].delegate).portraitOnly = NO;
}
zimmryan
  • 1,099
  • 10
  • 19
  • Unfortunately I am not in a position to use any libraries at this stage of the project for a small defect like this. – Tim Apr 23 '13 at 08:59
0

In iOS 6 what orientations view controllers are allowed to rotate to is controlled by the top-most full screen view controller, and autorotation methods are no longer called down the view controller hierarchy.

Instead of creating a subclass of the ABPersonViewController, create a subclass of UINavigationController with this code:

- (BOOL)shouldAutorotate
{
    return NO;
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}


- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;
}

Use this new subclass when creating the UINavigationController for the ABPersonViewController you are presenting. If the UINavigationController is not being presented modally (and is instead nested in a UITabBarController or another view controller), you will need to also put these methods in that view controller as well.

Andrew Theis
  • 933
  • 7
  • 15