)
}
}
)
(
}
{
)
)
(
)
(
(
{
}
)
(
)
}
)
)
{
(
(
)
)
}
)
(
}

IOS 16 Orientation Issues

With IOS 16 all my apps that support multiple orientations are now broken when rotating the device. Apple has broken my apps so many times with stuff like this. It’s so frustrating! Anyway…

Here is how I fixed it for my apps. In my main view controller I listen for orientation changes:

  1. [[NSNotificationCenter defaultCenter] addObserver:self
  2.                                       selector:@selector(orientationChange:)
  3.                                       name:UIDeviceOrientationDidChangeNotification
  4.                                       object:nil];

That has been that way for years… works fine and calls orientationChange.

  1. - (void)orientationChange:(NSNotification *)note {
  2.   UIDevice * device = note.object;
  3.   orient = device.orientation;
  4.  
  5.   // found this by searching around github https://github.com/liLeiBest/LZDependencyToolkit/blob/bca976207ef9674632d448e62ac425c22cecbc4f/LZDependencyToolkit/Classes/Category/UIViewController+LZForceRotation.m#L107
  6.   // glad that someone figured it out :D
  7.   if (@available(iOS 16, *)) {
  8.  
  9.     [self setNeedsUpdateOfSupportedInterfaceOrientations];
  10.     [self.navigationController setNeedsUpdateOfSupportedInterfaceOrientations];
  11.     NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
  12.     if (array.count) {
  13.  
  14.       UIWindowScene *scene = (UIWindowScene *)array[0];
  15.       UIWindowSceneGeometryPreferencesIOS *geometryperences = [[UIWindowSceneGeometryPreferencesIOS alloc] initWithInterfaceOrientations:(1 << orient)];
  16.       [scene requestGeometryUpdateWithPreferences:geometryperences errorHandler:^(NSError * _Nonnull error) {
  17.         NSLog(@"Orientation Error:%@", error);
  18.       }];
  19.     }
  20.   }
  21.   [self refreshUI];
  22. }

That big blob checking if IOS 16 is available is now necessary. Within my refreshUI method I use the width and height of the screen to position things. It seems that [[UIScreen mainScreen] bounds].size.height now takes a few hundred milliseconds to be updated with the current orientation. Maybe there is some new animation that needs to be disabled, but I have not been able to find it. So, I just delay 200ms and all seems ok:

  1. - (void) refreshUI {
  2.  
  3.   [self delay:0.2 callback:^(void){
  4.  
  5.     UIWindow* window=[[UIApplication sharedApplication] keyWindow];
  6.  
  7.     float t = window.safeAreaInsets.top;
  8.  
  9.     float b = window.safeAreaInsets.bottom;
  10.  
  11.     float l = window.safeAreaInsets.left;
  12.  
  13.     float r = window.safeAreaInsets.right;
  14.  
  15.     H = [[UIScreen mainScreen] bounds].size.height;
  16.     W = [[UIScreen mainScreen] bounds].size.width;
  17.  
  18.     // do some layout change stuff using `W` and `H`
  19.  
  20.   }];
  21. }

My delay method just looks like this:

  1. - (void)delay:(double)time callback:(void(^)(void))callback {
  2.   double delayInSeconds = time;
  3.   dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
  4.   dispatch_after(popTime, dispatch_get_main_queue(), callback);
  5. }

Beware of IOS dev – its riddled with this stuff…

// IOS // iPad // iPhone // ui
snippet.zone ~ 2021-24 /// {s/z}