Landscape ориентация для ViewController в приложении, разработанном под Portrait ориентацию
Столкнулась я на днях с интересной задачей - сделать возможным просмотр фото в Landscape ориентации в приложении, которое разрабатывается только под портретную ориентацию.
Эта статья - краткое руководство. Ниже вы найдете пример на Objective-C. Да, я написала пример на objc, ведь именно на этом языке мне пришлось решать задачу и как бы мы не хотели жить в мире Swift, правда такова, что большое количество легаси кода делает objc все еще актуальным.
Решение для Swift вы можете найти у Sunny Lee

1. Определяем поддерживаемую ориентацию в AppDelegate
Первым делом необходимо реализовать метод, который будет вызываться каждый раз при повороте девайса.
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
UIViewController *topViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];
if ([topViewController respondsToSelector:@selector(canRotate)]) {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
return UIInterfaceOrientationMaskPortrait;
}
Здесь мы проверяем, реализует ли topViewController селектор canRotate. Для того чтобы получить topViewController имплементируем там же метод topViewControllerInRootViewController:
- (UIViewController*)topViewControllerWithRootViewController:(UIViewController *)rootViewController {
if ([rootViewController isKindOfClass:UINavigationController.class]) {
UINavigationController *navigationController = (UINavigationController *)rootViewController;
return navigationController.visibleViewController;
}
if ([rootViewController isKindOfClass:UITabBarController.class]) {
UITabBarController *tabBarController = (UITabBarController *)rootViewController;
return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
}
if (rootViewController.presentedViewController) {
return rootViewController.presentedViewController;
}
return rootViewController;
}
2. Добавляем селектор canRotate во ViewController
Во ViewController, которому мы хотим разрешить менять ориентацию, добавляем метод canRotate.
- (void)canRotate {};
В данном случае метод пустой, т.к. нам достаточно его наличия. Вся логика содержится в AppDelegate. Однако это решение можно расширить, возвращая в методе конкретное значение UIInterfaceOrientationMask и обрабатывать его в AppDelegate, если вы хотите задать разное поведение для разных контроллеров.
3. Возвращаем портретную ориентацию при скрытии ротируемого ViewController
Так как приложение разрабатывается под портретную ориентацию и не предусматривает просмотр основных экранов в лэндскейп, нам нужно вернуть обратно портретную ориентацию при переходе из контроллера в Лэндскейп ориентации. Для этого в методе viewWillDisappear задаем девайсу нужную ориентацию.
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[UIDevice.currentDevice setValue:[NSNumber numberWithInt:UIInterfaceOrientationPortrait]
forKey:@"orientation"];
}
Заметка о баге
Работая над этой задачей я столкнулась с интересным юайным багом, когда на айфонах без челки после поворота в landscape, затем в портретную ориентацию с последующим закрытием экрана, navigationBar наплывал на statusBar. При этом при закрытии из горизонтальной ориентации либо до поворота в горизонтальную ориентацию navigationBar имел правильное положение.
После долгих поисков и изучения похожих вопросов в интернете, я зацепилась за фразу в документации о методе “presentViewController:animated:completion:” - “this method resizes the presented view controller's view based on the presentation style.” А именно его мы использовали. Оказывается, что для landscape режима по умолчанию используется UIModalPresentationFullScreen. А для самого экрана мы задавали UIModalPresentationCustom. Изменение последнего на FullScreen исправило этот баг.
Источники:
В своем решении я не оригинальна и в качестве источников, использовала решения, придуманные до меня, а так же официальную документацию.
В первую очередь, эта статья написана мною как конспект и попытка разложить по полочкам результат инвестигейта. Если я что-то упустила либо вы видите более изящное решение, буду рада комментариям.