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

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

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

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

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

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

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

Я не знаю, как правильно обращаться с этой ситуацией. Однако в 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]; } } 
Interesting Posts
Давайте будем гением компьютера.