iOS5 ломает обратные вызовы вращения UISplitViewController, как вызвать вручную? - PullRequest
12 голосов
/ 08 ноября 2011

Как и сообщалось в других вопросах здесь, в SO, iOS 5 изменяет способ обратного вызова ротации для контроллеров с разделенным представлением согласно этой заметке о выпуске.Это не обман (я думаю), так как я не могу найти другой вопрос о SO, который касается того, как настроить использование контроллера разделенного представления в iOS 5, чтобы справиться с изменением:

Обратные вызовы вращенияв iOS 5 не применяются для просмотра контроллеров, которые представлены на весь экран.Это означает, что если ваш код представляет контроллер представления поверх другого контроллера представления, а затем пользователь поворачивает устройство в другую ориентацию, то при отклонении базовый контроллер (то есть представляющий контроллер) не будет получать никаких обратных вызовов вращения.Однако обратите внимание, что представляющий контроллер получит вызов viewWillLayoutSubviews при повторном отображении, и свойство interfaceOrientation можно запросить из этого метода и использовать для правильной компоновки контроллера.

У меня проблемы с настройкойкнопка всплывающего окна в моем корневом контроллере разделенного вида (та, которая должна отображать вид левой панели во всплывающем окне, когда вы находитесь в портретной ориентации).Вот как последовательность запуска моего приложения работала в iOS 4.x, когда устройство находится в альбомном режиме:

  1. Установите контроллер разделенного вида в окно с [window addSubview:splitViewController.view]; [window makeKeyAndVisible];.Это приводит к тому, что splitViewController:willHideViewController:withBarButtonItem:forPopoverController: вызывается для делегата (т.е. имитирует альбомную ориентацию -> книжное вращение), даже если устройство уже находится в ландшафтном режиме.

  2. Представляет полноэкранный модальный режим (моя загрузкаэкран), который полностью покрывает разделенный вид внизу.

  3. Завершите загрузку и отключите модальный экран загрузки.Поскольку устройство находится в альбомном режиме, как показано в контроллере разделенного вида, это вызывает вызов splitViewController:willShowViewController:invalidatingBarButtonItem: для делегата (то есть имитация портрета -> альбомное вращение), что делает элемент панели кнопок недействительным, удаляя его справа- со стороны раздельного взгляда и оставления нас там, где мы хотим быть.Ура!

Итак, проблема в том, что из-за изменений, описанных в этой заметке о выпуске, все, что происходит внутри iOS 4.3, что приводит к вызову splitViewController:willShowViewController:invalidatingBarButtonItem:, больше не происходит в iOS 5Я попытался создать подкласс UISplitViewController, чтобы предоставить пользовательскую реализацию viewWillLayoutSubviews в соответствии с примечанием к выпуску, но я не знаю, как воспроизвести желаемую последовательность внутренних событий, которые запускает iOS 4.Я попробовал это:

- (void) viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    UINavigationController *rightStack = [[self viewControllers] objectAtIndex:1];
    UIViewController *rightRoot = [[rightStack viewControllers] objectAtIndex:0];
    BOOL rightRootHasButton = ... // determine if bar button item for portrait mode is there

    // iOS 4 never goes inside this 'if' branch
    if (UIInterfaceOrientationIsLandscape( [self interfaceOrientation] ) &&
        rightRootHasButton)
    {
        // Manually invoke the delegate method to hide the popover bar button item
        [self.delegate splitViewController:self
                    willShowViewController:[[self viewControllers] objectAtIndex:0]
                 invalidatingBarButtonItem:rightRoot.navigationItem.leftBarButtonItem];
    }
}

Это в основном работает, но не на 100%.Проблема в том, что сам вызов метода делегата не на самом деле делает недействительным элемент панели кнопок, поэтому при первом повороте в портретное положение система думает, что элемент панели кнопок по-прежнему установлен правильно и не пытаетсяпереустановить его.Только после повторного поворота в альбомную, а затем обратно в портретную систему система вернулась в правильное состояние и фактически установит элемент кнопки всплывающей панели в портретном режиме.

На основании этого вопроса , Я также попытался вызвать все обратные вызовы вращения вручную вместо запуска метода делегата, например:

// iOS 4 never goes inside this 'if' branch
if (UIInterfaceOrientationIsLandscape( [self interfaceOrientation] ) &&
    rightRootHasButton)
{
    [self willRotateToInterfaceOrientation:self.interfaceOrientation duration:0];
    [self willAnimateRotationToInterfaceOrientation:self.interfaceOrientation duration:0];
    [self didRotateFromInterfaceOrientation:self.interfaceOrientation];
}

Однако, похоже, это вызывает бесконечный цикл обратно в viewWillLayoutSubviews: (

Кто-нибудь знает, как правильно имитировать события ротации в стиле iOS4 для контроллера с разделенным видом, который появляется из-за полноэкранного модального режима? Или вам не следует имитировать их вообще, и есть ли другой метод наилучших практик,стать стандартом для iOS5?

Любая помощь действительно приветствуется, поскольку эта проблема удерживает нас от отправки нашего релиза исправления iOS5 в App Store.

1 Ответ

10 голосов
/ 09 ноября 2011

Я не знаю, как правильно справиться с этой ситуацией. Тем не менее, мне кажется, что следующее работает в iOS 5.

  1. В splitViewController:willHideViewController:withBarButtonItem:forPopoverController: сохраните ссылку на barButtonItem во что-то вроде self.barButtonItem. Переместите код для отображения кнопки в отдельный метод, скажем ShowRootPopoverButtonItem.

  2. В splitViewController:willShowViewController:invalidatingBarButtonItem:, очистить, что self.barButtonItem ссылка. Переместите код для отображения кнопки в отдельный метод, скажем InvalidateRootPopoverButtonItem.

  3. В viewWillLayoutSubviews, вручную показать или скрыть кнопку, в зависимости от ориентации интерфейса

Вот моя реализация viewWillLayoutSubviews. Обратите внимание, что вызов self.interfaceOrientation всегда возвращал портрет, поэтому я использовал statusBarOrientation.

- (void)viewWillLayoutSubviews
{
   if (UIInterfaceOrientationIsPortrait(
       [UIApplication sharedApplication].statusBarOrientation))
   {
      [self ShowRootPopoverButtonItem:self.barButtonItem];
   }
   else
   {
      [self InvalidateRootPopoverButtonItem:self.barButtonItem];
   }
}
...