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

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

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

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

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

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

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

  • Завершите загрузку и отпустите экран загрузки. Так как устройство находится в ландшафтном режиме, когда обнаружен контроллер разделенного вида, это вызывает вызов 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.

4b9b3361

Ответ 1

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

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

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

  • В viewWillLayoutSubviews вручную покажите или скройте кнопку, в зависимости от ориентации интерфейса

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

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