1

I have a strange bug in my app when my UI flow is as follows:

  1. The mainViewController is launched in Portrait orientation, and in turn it displays a LoginViewController with modalPresentationStyle set to UIModalPresentationFullScreen.

  2. I turn the loginViewController to landscape mode, enter credentials to login (the methods to authenticate the user are defined in the mainViewController).

  3. The loginViewController is dismissed (from the mainViewController) and a bunch of buttons are loaded onto the screen to indicate that it's the home screen.

Now my problem is that the button positions appear as if the app were in Portrait orientation even though the app was switched to Landscape while the loginViewController was presented.

Moreoever, this happens ONLY when the modalPresentationStyle is set to UIModalPresentationFullScreen! When I present it as a form sheet or a page sheet, everything works normally (I, however, need my loginViewController to be displayed FullScreen).

So far I've tried manually calling the shouldAutorotate method when the loginViewController is dismissed etc., and that solves the problem but seems like a shoddy workaround rather than a fix.

I've also tried calling the shouldAutorotate method of the mainViewController from the loginViewController, but this changes nothing.

Any ideas on how to fix the issue?

Vinod Vishwanath
  • 5,821
  • 2
  • 26
  • 40
  • What iOS version are you testing it on? – MANIAK_dobrii Dec 10 '12 at 18:10
  • I'm guessing you missed something simple. If you are adding your buttons after the login is done and when the device is already in landscape mode, you may need to reconsider the frames you are using for your buttons. Why not load the buttons etc before itself and just hide/unhide them.. so that you may not have to calculate the frame again for landscape mode? This is assuming your auto resizing masks are set properly. – Ravi Dec 11 '12 at 04:35

2 Answers2

1

Autorotation has changed in iOS 6. In iOS 6, the shouldAutorotateToInterfaceOrientation: method of UIViewController is deprecated. In its place, you should use the supportedInterfaceOrientations: and shouldAutorotate methods:

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskAllButUpsideDown;    
}

Modal ViewControllers no longer get rotation calls in iOS 6: The willRotateToInterfaceOrientation:duration:, willAnimateRotationToInterfaceOrientation:duration:, and didRotateFromInterfaceOrientation: methods are no longer called on any view controller that makes a full-screen presentation over itself—for example those that are called with: presentViewController:animated:completion:.

This answer will further explain the rotation changes in iOS 6


[EDIT] Completely different way is to register for rotation events. The advantage is that all objects can register for this, not only UIViewController. This is usually done when the view loads and stopped when the view disappears (put in dealloc here). The method in the selector is called when orientation changes (here it is orientationChanged:):

- (void)viewDidLoad {
    [super viewDidLoad];
    // Start generating device rotations and register for them
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
}

- (void)dealloc {
    // Deregister and stop generating device rotations
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    [super dealloc];
}
Community
  • 1
  • 1
Sverrisson
  • 17,970
  • 5
  • 66
  • 62
  • That's interesting. It partly answers my question. So how do I solve my problem now? I notice in the other answer you say "You can let the view controller that presents your modal view controller inform it of rotation." Could you elaborate, please? In my app, it's the root viewController that has failed to rotate - how can the child viewController inform the parent? I did try `[self.parent shouldAutorotate];` and it didn't work. – Vinod Vishwanath Dec 10 '12 at 19:15
  • 1
    I have added autorotation to my answer because that is the problem you also have as mentioned in the linked answer. You may also solve your problem by registering for rotation change events. – Sverrisson Dec 10 '12 at 20:46
  • 1
    I recently had to deal with this issue, and the workaround I used was to register for rotation change events like Hannes suggested. Also, note that if you're presenting the modal view this way, changes you make that are animated (in my case this was changing toolbar buttons) on the presenting view controller, which is not visible again until the modal view is closed, may not begin to animate until the modal view is actually closed. For these, don't call them with animation. – Anton Dec 10 '12 at 20:59
  • @HannesSverrisson not quite, but I think I may have stumbled upon the root of my problem: another thing that seems to have changed in iOS 6 is the way the height and width of a view are computed depending on the orientation. Earlier, I used to compute the screen height as `self.view.frame.size.height;` in Portrait orientation and `self.view.frame.size.width;` for Landscape orientation (vice versa for computing screen width). Now this relativism to the orientation seems to have been removed in iOS 6? Can you confirm that this is true? – Vinod Vishwanath Dec 12 '12 at 21:43
  • @VinodVishwanath the frameSize has not changed in iOS 6. But you may be calculating those on the view, before the view is rotated. You can get the view orientation simply by asking the view: self.interfaceOrientation; and the number shows the orientation. Log this out and then you will now if the view has rotated. – Sverrisson Dec 12 '12 at 23:38
  • That's right - the calculations were done in the `shouldAutorotate` method. My code is a bit murky - for some reason, the view width and height is slightly different when computed from `willRotateToInterfaceOrientation` as opposed to when it's computed from `shouldAutorotate` - I suspect this is because of some auto-resizing masks? I am, however, able to get some degree of control over rotation-event related communication between the presented ViewController and the presenting ViewController. Thanks for your help understanding the problem! I think I can solve it when it becomes a priority. – Vinod Vishwanath Dec 13 '12 at 09:13
  • @VinodVishwanath I am glad that you got control over the rotation issue. If you like I can send you code for registering rotation events. That may help you to make things more simple. – Sverrisson Dec 13 '12 at 10:30
  • @HannesSverrisson I'm simply overriding the `willRotateToInterfaceOrientation` and the `didRotateFromInterfaceOrientation` methods and passing the `toInterfaceOrientation` and `fromInterfaceOrientation` parameters to the presenting ViewController. Is there anything additional/more efficient I can do to "register" for rotation events? If so, some sample code would be very helpful! – Vinod Vishwanath Dec 13 '12 at 11:31
  • @VinodVishwanath I have added the code for registering for rotation changes above. You may use them if you need them. Or just create a new project and try them out. – Sverrisson Dec 13 '12 at 21:07
  • @HannesSverrisson Thanks, I'll try this and let you know how it works out. Note: I am using ARC mode for my app, so maybe I can deregister for rotation events in the `viewDidUnload` method? – Vinod Vishwanath Dec 14 '12 at 09:16
  • @VinodVishwanath the viewDidUnload is deprecated in iOS 6 and will never be called, so use dealloc instead. Dealloc is called even if you are using ARC. – Sverrisson Dec 14 '12 at 12:50
0
check this out.... may be this'll help...


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
     return (interfaceOrientation == UIInterfaceOrientationPortrait |interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown| interfaceOrientation == UIInterfaceOrientationLandscapeLeft | interfaceOrientation == UIInterfaceOrientationLandscapeRight);

}

-(NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown | UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight;
}

- (BOOL) shouldAutorotate
{
    return YES;
}
AKB
  • 132
  • 13