5

My application that supports both Portrait and Landscape orientations. I am presenting a UIViewController modally from a UIViewController located in a UITabBarController using the following code:

self.modalViewController = [[ModalViewController alloc] init];

[self presentViewController:self.modalViewController animated:YES completion:^{

}];

The ModalViewController is a controller that should only be seen by the user in Landscape. It should be able to rotate form LandscapeRight to LandscapeLeft. This is how it looks like:

@implementation ModalViewController

#pragma mark - UIViewController - Orientation

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate
{
    return YES;
}

#pragma mark - NSObject

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor greenColor];
}

#pragma mark - UIViewController - Status Bar

- (BOOL)prefersStatusBarHidden
{
    return YES;
}

@end

The controller slides up from the left side and covers the screen entirely 95% of the time. But 5% of the time, it slides up from the bottom and covers only the top half of the screen.

Here's how it looks when it's working fine:

enter image description here

And here's how it looks when it is not working fine:

enter image description here

I created a sample project that can be found here: https://github.com/TitouanVanBelle/Bug

There is a UI Testing target to help reproduce the issue but it rarely works.

Does anyone know why this is happening?

Titouan de Bailleul
  • 12,920
  • 11
  • 66
  • 121

3 Answers3

0

Your application is supporting Portrait, Landscape left and Landscape right orientations.

In ModalViewController.m update following method -

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait;
}

Your ModelViewController is only supporting landscape orientation hence this issue.

Instead of UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait you can use UIInterfaceOrientationMaskAllButUpsideDown as well.

EDIT 1

As per your requirement you can force rotate current orientation by updating following code in ModalViewController.m.

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.view.backgroundColor = [UIColor greenColor];

    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
}
Akshay Nalawade
  • 1,447
  • 2
  • 14
  • 29
  • But then users will be able to show the ModalViewController in landscape and in Portrait and I don't want that. I only want them to see it in landscape mode – Titouan de Bailleul Apr 24 '17 at 02:07
  • Ahhh.. that was not clear from your question. Give me some time I will update my answer – Akshay Nalawade Apr 24 '17 at 02:09
  • As mentioned in this comment http://stackoverflow.com/questions/26357162/how-to-force-view-controller-orientation-in-ios-8#comment43590053_26358192 the use of this API is insecure and might break at any iOS release. Also here the modal vc slides up from the bottom instead of from the left and the entire application rotates which is not what I'm looking for. – Titouan de Bailleul Apr 24 '17 at 02:49
0

This should be a comment, but I don't have enough reputation, so answer it is.

I think I've seen similar error.

The cause of the problem may be that orientation changes during transition in such a way that when viewDidLoad was called it was still portrait, but then changed to landscape and appropriate listener failed to respond properly (maybe because transition animation state is "in progress"?).

Some ideas on how to fix it:

  • listen to orientation change notifications and explicitly call self.view.setNeedsLayout when current orientation is landscape
  • in should autorotate return false if current orientation is portrait

Hope it helps.

Kitmap
  • 16
  • 3
0

I just tried to implement the same. I understood from your question is that you only want to show model VC in landscape mode. Here is the solution

1) Add presentation style to your model VC so it wont be displayed from the bottom or half screen. replace the FirstViewController code to following

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];    
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)),
    dispatch_get_main_queue(), ^{
        self.modalViewController = [[ModalViewController alloc] init];
        self.modalViewController.modalPresentationStyle = UIModalPresentationFullScreen;

        NSAssert([NSThread currentThread] == [NSThread mainThread], @"FAIL");

        [self presentViewController:self.modalViewController animated:YES completion:^{}];
    });
}

2) In Model VC change the ovveriden method supportedInterfaceOrientations to this

-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight;
}

3) To get Clear Idea of rotation add a view on Model VC so it will be clear whether the view is rotating or not. Add Following code in Model VC

-(void)viewDidLoad    
{
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor greenColor];
    UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 100)];
    view.backgroundColor = [UIColor redColor];
    [self.view addSubview:view];
}

Now after doing all this if you try to open the app it will open the Model VC in landscape mode only which can be rotated either in landscape left or right but potrait mode will be disabled.

anuragtk
  • 89
  • 3