iOS 16 unexpected rotation behaviour

Is anyone facing any issue with rotation on iOS 16? It seems to introduce some unexpected behaviour.

For example, if we're on a Master screen that supports all orientations and device is in Landscape mode, presenting/pushing another Details screen that only supports Portrait automatically brings the app to Portrait with no animations. While on iOS 15 or earlier, the app remains at Landscape and only rotates to Portrait when physical device's orientation changes.

Then if we dismiss/pop back to Master screen, the app again unexpectedly rotates from Portrait to Landscape with no animations.

Looks like a regression bug on iOS 16 part of some recent deprecations related to shouldAutorotate or UIDevice.setValue:forKey: as well as the introduction of setNeedsUpdateOfSupportedInterfaceOrientations.

Post not yet marked as solved Up vote post of ntduyet Down vote post of ntduyet
14k views
  • Yeah I need to prevent screen rotation while the user is recording video, but with deprecation of shouldAutorotate I don't know how to do this. setNeedsUpdateOfSupportedInterfaceOrientations doesn't seem to be found when trying to compile and supportedInterfaceOrientations is read only. Currently, I've got a bunch of iOS16 users complaining.

Add a Comment

Replies

Somewhat related, the documentation for setNeedsUpdateOfSupportedInterfaceOrientations https://developer.apple.com/documentation/uikit/uiviewcontroller/4047535-setneedsupdateofsupportedinterfa states "By default, this method animates any changes to orientation. To perform a nonanimated update, call this method from performWithoutAnimation(_:)." and when I attempt to use performWithoutAnimation, it randomly doesn't have an effect half of the time, and I see the unwanted interface orientation change animation.

I had a similar problem. Calling setViewController:animated: of UINavigationController to replace topViewController (which is landscape) with a new landscape viewController makes the viewController try to rotate to portrait first, then suddenly change to landscape. Here is the code to reproduce this bug.

#import "ViewController.h"

@interface UINavigationController (Replace)

- (void)replaceTopWithViewController:(UIViewController *)viewController
              animated:(BOOL)animated;

- (void)replaceViewControllersInRange:(NSRange)range
         withViewControllers:(NSArray<UIViewController *> *)viewControllers
               animated:(BOOL)animated;

@end

@implementation UINavigationController (Replace)

- (void)replaceViewControllersInRange:(NSRange)range
         withViewControllers:(NSArray<UIViewController *> *)viewControllers
               animated:(BOOL)animated {
  NSMutableArray *VCs = [self.viewControllers mutableCopy];
  [VCs replaceObjectsInRange:range withObjectsFromArray:viewControllers];
  [self setViewControllers:[VCs copy] animated:animated];
}

- (void)replaceTopWithViewController:(UIViewController *)viewController animated:(BOOL)animated {
  [self replaceViewControllersInRange:NSMakeRange(self.viewControllers.count - 1, 1)
          withViewControllers:@[viewController]
                animated:animated];
}

@end

@implementation NavigationController

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

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
  return [self.topViewController supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
  return [self.topViewController preferredInterfaceOrientationForPresentation];
}

@end


@interface ThirdViewController : UIViewController

@end

@implementation ThirdViewController

- (BOOL)shouldAutorotate {
  return YES;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  self.view.backgroundColor = UIColor.redColor;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskLandscapeRight;
}

@end

@interface SecondViewController : UIViewController

@end

@implementation SecondViewController

- (BOOL)shouldAutorotate {
  return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskLandscapeRight;
}

- (void)viewDidAppear:(BOOL)animated {
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    ThirdViewController *controller = [[ThirdViewController alloc] init];
    [self.navigationController replaceTopWithViewController:controller animated:YES];
  });
}

@end

@interface ViewController ()

@end

@implementation ViewController

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskPortrait;
}

- (void)viewDidLoad {
  [super viewDidLoad];

  self.view.backgroundColor = UIColor.whiteColor;
}

- (void)viewDidAppear:(BOOL)animated {
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    SecondViewController *controller = [[SecondViewController alloc] init];
    [self.navigationController pushViewController:controller animated:YES];
  });
}

@end


I am facing some similar issues with my app too.

https://developer.apple.com/forums/thread/715052#715052021

I fixed my version of this issue by updating the supportedInterfaceOrientations and then calling self.setNeedsUpdateOfSupportedInterfaceOrientations() wrapped in an iOS version check. My VC now behaves the same as before iOS 16 update.

  // MARK: START Orientation Logic
  // For iOS 16+ devices need to update `supportedInterfaceOrientations` value for
  // supported orientations and then call `setNeedsUpdateOfSupportedInterfaceOrientations()`
  // before app will recognize the new orientation change
  var scanModeEnabled = false {
    didSet {
      if #available(iOS 16.0, *) {
        self.setNeedsUpdateOfSupportedInterfaceOrientations()
      }
    }
  }
   
  override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
    if scanModeEnabled {
      return .all
    } else {
      return .portrait
    }
  }

 // This is deprecated on iOS 16 and higher
 override var shouldAutorotate: Bool {
    return true
  }
  // MARK: END Orientation Logic
  • Hi @Morssel_K. I believe that the way you solved it, I can solve it too. Under iOS 16, supportedInterfaceOrientations would have been automatically set by shouldAutorotate, but I think that setNeedsUpdateOfSupportedInterfaceOrientations() must be called explicitly as shouldAutorotate is deprecated. But I'm curious, when did you toggle the scanModeEnabled value? thanks.

  • Hi @Morssel_K, could you please share the full code? Where do you set the scanModeEnabled value as @Nury asked. Thanks :)

  • After the condition (if #available(iOS 16.0, *)) is established

Add a Comment

Yes i am using iphone 8. Though its a 4 year old model but still working great and getting ios 16 update. But after ios 16 there is a specific rotation bug with Antutu appoication. I enabled disabled the auto rotation but the app is running with portrait mode and then close in the middle of benchmark test. Dont know how to resolve it

In this context: iOS 16 seems to have introduced a new behavior in which the gyroscopes of many (all?) iPhone models stay on despite the display is being turned off which leads to frequent unexpected screen rotations after unlocking the phone.

Example:

  • you're using the phone in portrait
  • you're locking it and putting it sideways into your pocket
  • you're pulling it out again
  • you're unlocking it while holding it relatively flat
  • and suddenly your last app is in landscape.

This behavior might be related to the new always-on display of iPhone 14 Pro, but in any case I find it super annoying and I can't quite understand why. - Up until iOS 15 the phone didn't care about its orientation while the display was turned off, now I have my last app in landscape n times a day after unlocking the phone.

Video: https://photos.app.goo.gl/m2w1nhPswr7EGJ1G6

  • Updated video link: https://youtube.com/shorts/L5U0mH2t9Go

Add a Comment

We are currently using react-native for our application development and have come across a similar issue in the UIView when the orientation changes from portrait to landscape on navigation. The UIView seems to stay in portrait mode and it looks like half of the screen content has been sliced off. The same happens while navigating back from landscape to portrait screens where the screen appears to be stretched as the content holds landscape mode. Also, we are only able to replicate this on a physical device more precisely iPhone 13 and above and not on the respective emulators. To fix this behavior we have used react-native-orientation-locker package which covers 90% of the scenarios but for some edge cases (like when receiving third-party push notifications), we still face this issue. Any help or thoughts on this would be much appreciated as it is currently blocking some of our core functionalities.

@lighthouse-learning I'm facing a similar issue when entering a video in FullScreen mode on landscape. When exiting, the layout attempts to switch to portrait and broken (see attached imagen) My app in develop in Ionic + cordova.

Have you found any solutions or updates regarding this issue?