iPhone Пейзаж FAQ и решения

Здесь было много путаницы и множество соответствующих вопросов о том, как можно реализовать приложения iPhone с надлежащей обработкой для автоповорота в альбомном / портретном режиме. Особенно сложно реализовать такое приложение, когда требуется запуск в ландшафтном режиме. Наиболее распространенным наблюдаемым эффектом являются зашифрованные макеты и области экрана, где касания больше не распознаются.

Простой поиск вопросов с тегами iphone а также landscape выявляет эти проблемы, которые возникают при определенных сценариях:

Был представлен ряд различных решений, некоторые из которых включают полностью настраиваемую анимацию с помощью CoreGraphics, в то время как другие основаны на наблюдении, что первый контроллер представления, загруженный из основного пера, всегда отображается правильно.

Я потратил значительное количество времени на изучение этой проблемы и, наконец, нашел решение, которое является не только частичным, но и должно работать при всех этих обстоятельствах. Я намерен в этом посте CW предоставить своего рода FAQ для других, имеющих проблемы с UIViewControllers в ландшафтном режиме.

Пожалуйста, оставьте отзыв и помогите улучшить качество этой публикации, включив любые связанные наблюдения. Не стесняйтесь редактировать и публиковать другие / лучшие ответы, если вы знаете какие-либо.

6 ответов

Решение

Что в документации:

В вашем контроллере представления переопределите shouldAutorotateToInterfaceOrientation: для объявления поддерживаемых ориентаций интерфейса. Это свойство будет / должно проверяться инфраструктурой контроллера при каждом изменении ориентации устройства.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation
{
   return  (orientation == UIInterfaceOrientationLandscapeRight);
}

Это абсолютный минимум, который необходим вашему контроллеру представления. Если вы хотите запустить ваше приложение в ландшафтном режиме, вам нужно добавить следующий ключ к вашему .plist файл:

<key>UIInterfaceOrientation</key>
<string>UIInterfaceOrientationLandscapeRight</string>

Apple рекомендует запускать приложения только в альбомной ориентации в режиме альбомной ориентации (см. HIG в разделе "Руководства по работе с пользователями"> "Начать мгновенно")

Что нет в документации:

Немного предыстории:

Каждый раз, когда вы пытаетесь загрузить другой контроллер представления, отличный от того, который загружен из основного пера, ваш контроллер представления не опрашивается ни о поддерживаемых ориентациях интерфейса, ни о его кадре. Только первый контроллер представления, привязанный к окну, будет правильно размещен.

Другие люди предложили использовать "MasterViewController", подключенный к главному окну, к которому другие контроллеры добавляют свои представления в качестве подпредставлений, а не подключать непосредственно к окну. Хотя я нашел, что это решение является жизнеспособным вариантом, оно не работает корректно в случае модальных контроллеров представления, добавленных к тем упомянутым подпредставлениям. Существует также проблема, если у вас есть некоторые подпредставления, которые должны иметь возможность автоматического поворота (что будет предотвращать главный контроллер).

Использование недокументированных API для навязывания определенной ориентации интерфейса также не вариант.

Решение:

Наилучшее решение, которое я нашел, - это модификация обходного пути MasterViewController. Вместо использования собственного "MasterViewController", UINavigationController со скрытой панелью навигации и скрытой панелью вкладок. Если все другие представления выталкиваются / извлекаются из стека навигации этого контроллера, автоматическое вращение контроллеров в этом стеке будет управляться правильно.

Модальные контроллеры представлены через presentModalViewController:animated: с любого из контроллеров представления на UINavigationControllerНавигационный стек будет вращаться и отображаться с правильной компоновкой. Если вы хотите, чтобы ваш модальный контроллер вида мог вращаться с ориентацией, отличной от ориентации родительского контроллера вида, вам нужно вернуть желаемую ориентацию из shouldAutorotateToInterfaceOrientation метод родительского контроллера, в то время как модальное представление представлено. Для того, чтобы правильно восстановить ориентацию интерфейса, когда модальный контроллер уволен, вы должны убедиться, shouldAutorotateToInterfaceOrientation возвращает желаемую ориентацию для родительского контроллера перед вызовом dismissModalViewController:animated:, Вы можете использовать частный BOOL на вашем контроллере представления, чтобы управлять этим (например, BOOL isModalMailControllerActive_).

Я скоро добавлю пример кода. Сейчас уже поздно. Пожалуйста, дайте мне знать, если остались какие-либо нерешенные вопросы или что-то неясно в этом посте Не стесняйтесь редактировать и улучшать.

У меня было интересное требование для приложения IOS:

main viewController должен быть только альбомным, но все остальные (которые можно вытолкнуть из основного) могут быть альбомными и портретными.

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

Чтобы сохранить ландшафт основного view-контроллера, независимо от того, с какой ориентацией он был вытолкнут / выдвинут, я сделал следующее: (в viewWillAppear:)

//set statusbar to the desired rotation position
[[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];

//present/dismiss viewcontroller in order to activate rotating.
UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
[self presentModalViewController:mVC animated:NO];
[self dismissModalViewControllerAnimated:NO];

Надеюсь, это кому-нибудь поможет!

PSTested на SDK 3.2.5 IOS 5.0.1.

PS Спасибо за всю информацию в этом FAQ!

Что касается второго пункта, если вы хотите использовать pushViewController для перехода из режима "Только портрет" в режим "Только пейзаж", я обнаружил один простой способ взломать следующий код в viewDidLoad вашего контроллера:

UIViewController *viewController = [[UIViewController alloc] init];
[self presentModalViewController:viewController animated:NO];
[self dismissModalViewControllerAnimated:NO];
[viewController release];

Я разрабатываю приложение для iPad, которое при запуске отображает вертикальную прокрутку галереи для просмотра множества элементов. В ландшафтном режиме 4 элемента в поперечнике. В портрете их три. При повороте ориентации iPad предполагается обновить галерею, чтобы элементы аккуратно помещались на экране. Затем я дважды нажимаю на элемент, чтобы перейти к модальному виду этого элемента. Затем я делаю вещи с этим предметом. Наконец я отклоняю модальное представление.

Во время обновления или изменения ориентации представление галереи вычисляет количество элементов для отображения на основе ширины экрана (или высоты) и текущей ориентации из UIViewController.interfaceOrientation.

У меня была проблема с тем, чтобы заставить это работать правильно. Иногда он отображал только два элемента в альбомной ориентации после того, как я закрыл модальное диалоговое окно.

Сначала я использовал значения UIViewController.view.frame.size, чтобы вычислить количество элементов галереи. Когда модальное представление было отклонено, этот размер кадра был неправильным, например, ширина и высота были изменены на противоположные, даже если ориентация не изменилась во время отображения модального диалога.

Я перешел к использованию делегата приложения ([[UIApplication sharedApplication] делегат]] и взятию window.frame.size, чтобы вычислить количество элементов галереи для отображения. Размер window.frame.size остается корректным при изменениях ориентации и модальных диалоговых окнах. Элементы галереи теперь отображаются правильно.

Я хотел бы добавить к ответу Йоханнеса (используя UINavigationController в качестве MasterViewController).

Недостаток, который я обнаружил, состоит в том, что ViewControllers, которые недавно помещены в стек навигации главного виртуального канала, не приспосабливаются к любым предшествующим изменениям ориентации. Короче говоря, VC, уже находящиеся в стеке, вращаются, контроллеры модального представления, представленные из них, также поворачиваются, но вновь добавленные VC не вращаются.

Я пробовал много хитростей, чтобы исправить это, прежде чем нашел тот, который работает. Большинство работает только для pushViewController: с анимированным значением YES.

Чтобы полностью решить проблему, я подкласс UINagivationController и переопределить pushViewController:animated: следующее:

- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    // Correctly autoOrient the given view controller
    [self presentModalViewController:viewController animated:NO];
    [self dismissModalViewControllerAnimated:NO];

    // Push it as normal (now in its correct orientation)
    [super pushViewController:viewController animated:animated];
}

Временное (и совершенно незаметное) представление контроллера представления позволяет ему получать обновление ориентации. Затем его можно поместить в стек навигации в правильной ориентации.

Пожалуйста, дайте мне знать, если это работает для вас. Все обновления и улучшения приветствуются!

Наконец, я очень рекомендую подход Йоханнеса к управлению ротацией.

РЕДАКТИРОВАТЬ: Обновление на выталкивающих контроллеров представления из стека

Кажется, что все селекторы, связанные с popViewController, сходят с ума, когда выполняются с анимацией: ДА. В частности, контроллер представления анимирован в неправильном направлении. Вы можете использовать animated:NO и ограничивать использование таких анимаций другими UINavigationControllers, расположенными глубже в вашей иерархии (то есть теми, которые вы помещаете в стек корневого контроллера навигации).

Любой вклад с благодарностью.

Это будет работать...

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    UIView *view = [window.subviews objectAtIndex:0];
    [view removeFromSuperview];
    [window addSubview:view];
Другие вопросы по тегам