Как поддерживать представление ориентации контроллера представления при отключении контроллера модального представления?
У меня есть это приложение, над которым я работаю, и мне нужны ВСЕ мои контроллеры просмотра, кроме одного, чтобы быть в портрете.
Единственный один контроллер просмотра, который мне особенно нужен, чтобы он мог поворачиваться в любую ориентацию телефона.
Для этого я представляю его модально (не встроенный в NavigationController)
Итак (например) моя структура выглядит так:
- окно - портрет
- контроллер корневого представления (UINavigationController - Portrait)
- контроллер домашнего просмотра (UIViewController - Portrait)
- подробный просмотр контроллера (UIViewController - Portrait)
- .
- .
- .
- modal view controller (UIVIewController - All)
Теперь, когда я увольняю мой контроллер модального представления в ландшафтном положении, мой родительский контроллер представления также поворачивается, хотя он не поддерживает эту ориентацию.
Все UIViewControllers
и UINavigaionControllers
в приложении наследуются от тех же общих классов, которые имеют эти методы:
override func supportedInterfaceOrientations() -> Int
{
return Int(UIInterfaceOrientationMask.Portrait.toRaw())
}
Модный контроллер просмотра переопределяет этот метод еще раз, и он выглядит так:
override func supportedInterfaceOrientations() -> Int
{
return Int(UIInterfaceOrientationMask.All.toRaw())
}
Обновление 1
Похоже, что это происходит только на бета-версии iOS8.
Кто-нибудь знает, есть ли что-то, что изменилось в отношении вращения контроллера просмотра, или это просто ошибка в бета-версии?
Ответы
Ответ 1
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if ([self.window.rootViewController.presentedViewController isKindOfClass: [SecondViewController class]])
{
SecondViewController *secondController = (SecondViewController *) self.window.rootViewController.presentedViewController;
if (secondController.isPresented)
return UIInterfaceOrientationMaskAll;
else return UIInterfaceOrientationMaskPortrait;
}
else return UIInterfaceOrientationMaskPortrait;
}
И для Swift
func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow) -> Int {
if self.window?.rootViewController?.presentedViewController? is SecondViewController {
let secondController = self.window!.rootViewController.presentedViewController as SecondViewController
if secondController.isPresented {
return Int(UIInterfaceOrientationMask.All.toRaw());
} else {
return Int(UIInterfaceOrientationMask.Portrait.toRaw());
}
} else {
return Int(UIInterfaceOrientationMask.Portrait.toRaw());
}
}
Подробнее см. ссылку
Ответ 2
У меня такая же проблема с приложением, и после нескольких дней экспериментов я придумал решение, которое не очень приятно, но сейчас оно работает. Я использую метод делегата application:supportedInterfaceOrientationsForWindow:
в appdelegate.
Я создал тестовый проект и поместил его здесь на github (включая GIF, который показывает результат...)
//обратите внимание: это не быстро, но я надеюсь, что это поможет в любом случае
Ответ 3
После долгих экспериментов я убежден, что это "особенность" iOS 8.
Если вы думаете об этом, это имеет смысл, потому что оно наступает долгое время.
-
В, скажем, iOS 4, было возможно принудительное вращение приложения при смене контроллеров представления в контроллере панели вкладок и контроллере навигации, а также при представлении/увольнении контроллера.
-
Тогда в iOS 6 стало невозможно заставить вращение приложения, кроме как при представлении/увольнении контроллера представления (как я объяснил во многих ответах, таких как этот).
-
Теперь, в iOS 8, я предполагаю, что будет невозможно принудительно направить вращение приложения (за исключением запуска). Он может предпочесть определенную ориентацию, так что, когда она находится в этой ориентации, она останется там, но не может заставить приложение перейти в эту ориентацию.
Вместо этого ваш контроллер просмотра должен "адаптироваться". Есть несколько видеороликов WWDC 2014, посвященных "адаптации", и теперь я начинаю понимать, что это одна из причин, почему это так важно.
EDIT: В семени 4, похоже, эта функция (принудительное вращение при представлении и увольнении) возвращается!
Ответ 4
У нас развернуто приложение с ландшафтным контроллером, который представляет собой контроллер просмотра только для портрета. Был рассмотрен Apple на iOS 8. Мы только переопределяем supportInterfaceOrientations.
Стоит отметить, что мы обнаружили множество различий между бетами 3,4 и 5. В итоге нам пришлось ждать GM, прежде чем предпринимать согласованные усилия по обновлению нашего приложения для iOS 8.
Вам нужно быть очень осторожным в iOS 8, чтобы убедиться, что вы этого не делаете:
[self dismissViewControllerAnimated:YES completion:nil]
[self presentViewController:vc animated:YES completion:nil]
Если исходящий vc является портретом, а входящий - альбомным, некоторые рамы представления могут в конечном итоге перепутаться. Представьте входящий vc в блоке завершения вызова увольнения вместо этого.
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:vc animated:YES completion:nil]
}];
Ответ 5
В контроллере корневого представления попробуйте добавить:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
Работал для меня.
Ответ 6
Swift 3.0 OR Выше, Просто проверьте свойство isBeingDismissed представленного контроллера представления. Ниже приведен пример кода. Это будет вращать представление контроллера представления в портретный режим сразу после отклонения представленного контроллера представления.
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController)
{
if rootViewController.canRotateVC == true
{
if baseVC.isBeingDismissed == false
{
return .allButUpsideDown
}
}
}
return .portrait}
вы можете получить topController по коду:
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController?{
if (rootViewController == nil) { return nil }if (rootViewController.isKind(of: (UITabBarController).self))
{
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
}
else if (rootViewController.isKind(of:(UINavigationController).self))
{
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
}
else if (rootViewController.presentedViewController != nil)
{
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController }
Ответ 7
Это на самом деле проще и может быть выполнено без каких-либо дополнительных свойств (здесь пример с AVPlayerViewController
):
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
if ([self.window.rootViewController.presentedViewController isKindOfClass: [AVPlayerViewController class]])
return self.window.rootViewController.presentedViewController.isBeingDismissed ?
UIInterfaceOrientationMaskPortrait : UIInterfaceOrientationMaskAll;
else
return UIInterfaceOrientationMaskPortrait;
} else {
return UIInterfaceOrientationMaskAll;
}
}
Ответ 8
Удивительный вопрос и замечательный ответ @ZaEeM ZaFaR! Объединив его ответ с это привело меня к большому и более универсальному решению.
Недостатком первого ответа является то, что вам нужно управлять переменной isPresented
в каждом контроллере представления, который допускает вращения. Кроме того, вам нужно расширить проверку и включить в supportedInterfaceOrientationsForWindow
для каждого vc, который позволяет вращать.
Недостатком второго ответа является то, что он не работает; он также вращает презентацию vc при отклонении представленного vc.
Это решение разрешает вращение во всех vc, где вы помещаете canRotate() {} и не поворачиваете презентацию vc.
Swift 3:
В AppDelegate.swift:
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if let rootViewController = self.topViewControllerWithRootViewController(rootViewController: window?.rootViewController) {
if (rootViewController.responds(to: Selector(("canRotate")))) {
// Unlock landscape view orientations for this view controller if it is not currently being dismissed
if !rootViewController.isBeingDismissed{
return .allButUpsideDown
}
}
}
// Only allow portrait (standard behaviour)
return .portrait
}
private func topViewControllerWithRootViewController(rootViewController: UIViewController!) -> UIViewController? {
if (rootViewController == nil) {
return nil
}
if (rootViewController.isKind(of: UITabBarController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UITabBarController).selectedViewController)
} else if (rootViewController.isKind(of: UINavigationController.self)) {
return topViewControllerWithRootViewController(rootViewController: (rootViewController as! UINavigationController).visibleViewController)
} else if (rootViewController.presentedViewController != nil) {
return topViewControllerWithRootViewController(rootViewController: rootViewController.presentedViewController)
}
return rootViewController
}
В каждом контроллере просмотра, где должно быть разрешено вращение:
func canRotate(){}
Ответ 9
У меня была такая же проблема, наконец, найдено решение открыть контроллер модального представления в другом UIWindow, и он работал плавно.
Стек -
iOS8 - предотвратить вращение при представлении viewController
Для кода:
https://github.com/OrenRosen/ModalInWindow