iOS5 нарушает обратные вызовы вращения UISplitViewController, как вызвать вручную?

Как было сообщено в других вопросах здесь, на 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.


person glenc    schedule 08.11.2011    source источник


Ответы (1)


Я не знаю, как правильно справиться с этой ситуацией. Однако в 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];
   }
}
person Noah Harrison    schedule 09.11.2011
comment
Привет, Ной - спасибо за решение - оно у меня тоже работает. Это немного прискорбно, потому что viewWillLayoutSubviews вызывается гораздо чаще, чем события вращения, поэтому запихивание там всей логики скрытия / отображения кнопок означает, что он запускается намного чаще, но похоже, что это способ iOS5. этот материал сейчас. - person glenc; 09.11.2011