Часто задаваемые вопросы и решения для iPhone

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

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

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

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

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

Ответ 1

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

В вашем контроллере просмотра переопределить 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 контроллера parent, тогда как модальный вид Представлен. Чтобы правильно восстановить ориентацию интерфейса при отключении модального контроллера, вы должны убедиться, что shouldAutorotateToInterfaceOrientation возвращает желаемую ориентацию родительского контроллера до вызова dismissModalViewController:animated:. Для управления этим (например, BOOL isModalMailControllerActive_) можно использовать закрытый BOOL на вашем контроллере просмотра.

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

Ответ 2

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

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

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

Чтобы сохранить основной ландшафт viewcontroller, независимо от того, какую ориентацию он выскочил/нажал, я сделал следующее: (in 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];

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

P.S.Tested на sdk 3.2.5 ios 5.0.1.

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

Ответ 3

Для второй маркерной точки, если вы хотите использовать pushViewController для перехода из режима "Портрет только" в "Ландшафтный", один простой взломанный я нашел, чтобы поставить следующий код в ваш нажатый контроллер viewDidLoad:

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

Ответ 4

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

Недостаток, который я обнаружил, заключается в том, что ViewControllers, которые недавно были нажаты на главный стек навигации VC, не корректируют никаких изменений ориентации. Короче говоря, 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, сходят с ума, когда выполняются с анимированными: ДА. В частности, контроллер вида анимирован в неправильном направлении. Вы можете использовать анимированные: НЕТ и ограничить использование таких анимаций другим UINavigationControllers глубже в своей иерархии (т.е. Те, которые вы нажимаете на корневую панель контроллера навигации).

Приветствуется любой ввод.

Ответ 5

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

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

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

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

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

Ответ 6

Это сработает...

UIWindow *window = [[UIApplication sharedApplication] keyWindow];
    UIView *view = [window.subviews objectAtIndex:0];
    [view removeFromSuperview];
    [window addSubview:view];