iPhone Пейзаж FAQ и решения
Здесь было много путаницы и множество соответствующих вопросов о том, как можно реализовать приложения iPhone с надлежащей обработкой для автоповорота в альбомном / портретном режиме. Особенно сложно реализовать такое приложение, когда требуется запуск в ландшафтном режиме. Наиболее распространенным наблюдаемым эффектом являются зашифрованные макеты и области экрана, где касания больше не распознаются.
Простой поиск вопросов с тегами iphone
а также landscape
выявляет эти проблемы, которые возникают при определенных сценариях:
Только в альбомном приложении iPhone с несколькими кончиками: приложение запущено в альбомном режиме, вид с первого кончика отображается нормально, все изображения, загруженные из другого кончика, отображаются неправильно.
Переключение режима Iphone Landscape в режим Portraite при загрузке нового контроллера: не требует пояснений
iPhone: только в альбомной ориентации после первого добавления addSubview UITableViewController не вращается должным образом: та же проблема, что и выше.
Приложение-шаблон для iPhone только для ландшафта: ошибки компоновки, контроллер, похоже, не распознает, что представление должно быть повернуто, но отображает обрезанное портретное представление в альбомном режиме, в результате чего половина экрана остается пустой.
presentModalViewController в альбомной ориентации после портретной viewController: модальные представления также отображаются неправильно.
Был представлен ряд различных решений, некоторые из которых включают полностью настраиваемую анимацию с помощью 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];