Подтвердить что ты не робот

Как поддерживать представление ориентации контроллера представления при отключении контроллера модального представления?

У меня есть это приложение, над которым я работаю, и мне нужны ВСЕ мои контроллеры просмотра, кроме одного, чтобы быть в портрете. Единственный один контроллер просмотра, который мне особенно нужен, чтобы он мог поворачиваться в любую ориентацию телефона.

Для этого я представляю его модально (не встроенный в 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. Кто-нибудь знает, есть ли что-то, что изменилось в отношении вращения контроллера просмотра, или это просто ошибка в бета-версии?

4b9b3361

Ответ 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(){}