Как ограничить авторотацию одной ориентацией для некоторых видов, позволяя при этом все ориентации на других?

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

У меня очень простое демо-приложение, которое показывает странность, и я сделал видео, показывающее его в действии.

  • Загрузите приложение (проект XCode)
  • Просмотреть classы как сущность (довольно длинные)
  • Смотрите видео с вопросом (YouTube, 2m43s)

Настройка очень простая: три controllerа представлений, называемые FirstViewController , SecondViewController и ThirdViewController расширяют AbstractViewController который показывает метку с именем classа и возвращает YES для shouldAutorotateToInterfaceOrientation: когда устройство находится в портретной ориентации. SecondViewController переопределяет этот метод, чтобы разрешить все вращения. Все три конкретных classа добавляют несколько цветных квадратов, чтобы можно было перемещаться между представлениями, нажимая и выталкивая controllerы в / из UINavigationController . Я бы сказал, что это очень простой сценарий.

Если вы держите устройство в портретной или альбомной ориентации, это результат, который я бы не только хотел достичь, но и ожидал. На первом изображении вы видите, что все представления «вертикальные», а во втором вы видите, что только второй controller просмотра вращает ориентацию устройства. Чтобы быть ясным, должно быть возможно перемещаться со второго представления в ландшафтном режиме на третье, но поскольку эта третья только поддерживает портретную ориентацию, ее следует показывать только в портретной ориентации. Самый простой способ убедиться, что результаты в порядке, – это посмотреть на позицию несущей.

Ожидаемая ориентация изображения для устройства в портретном режимеОжидаемая ориентация изображения для устройства в ландшафтном режиме

Но этот вопрос здесь, потому что фактический результат совершенно другой. В зависимости от того, с каким видом вы находитесь, когда вы вращаете устройство, и в зависимости от того, какой вид вы переходите к следующему, точки зрения не будут вращаться (что конкретно, метод didOrientFromInterfaceOrientation: никогда не вызывается). Если вы находитесь в ландшафте на втором и переходите к третьему, он будет иметь ту же ориентацию, что и второй (= плохой). Однако, если вы переходите со второго назад на первое, экран будет вращаться в режиме принудительного портрета, а панель оператора будет находиться на физическом верхнем углу устройства, независимо от того, как вы держите его. Видео показывает это более подробно.

Фактическая ориентация изображения для устройства в ландшафтном режиме

Мой вопрос двоякий:

  1. Почему первый controller просмотра вращается назад, но не третий?
  2. Что нужно сделать, чтобы получить правильное поведение из ваших представлений, когда вы хотите, чтобы некоторые виды отображались на автороте, но не на других?

Cheers, EP.

РЕДАКТИРОВАТЬ: В крайнем случае, прежде чем положить на него щедрость, я полностью переписал этот вопрос, чтобы быть короче, яснее и, надеюсь, более привлекательным, чтобы дать ответ.

Короткий ответ заключается в том, что вы используете UINavigationController, и это не будет работать так, как вы этого хотите. Из документов Apple:

Почему мой UIViewController не будет вращаться вместе с устройством?

Все controllerы детского просмотра в вашем UITabBarController или UINavigationController не согласны с общим набором ориентации.

Чтобы убедиться, что все controllerы вашего дочернего представления вращаются правильно, вы должны реализовать shouldAutorotateToInterfaceOrientation для каждого controllerа представления, представляющего каждую вкладку или уровень навигации. Каждый из них должен согласиться с той же ориентацией, что и для этого поворота. То есть, все они должны возвращать YES для одинаковых позиций ориентации.

Здесь вы можете узнать больше о проблемах поворота .

Вам придется сворачивать ваше собственное управление стеком / controllerом стека за то, что вы хотите сделать.

Сделайте bolean в делетете приложения, чтобы контролировать, какую ориентацию вы хотите, например, сделать bool, чтобы включить Portrait и в вашем controllerе вида, который вы хотите разрешить Portrait, включив его совместно используемым приложением

в вашем controllerе просмотра, где вы хотите включить или отключить любую ориентацию, которую вы хотите.

 ((APPNAMEAppDelegate *)[[UIApplication sharedApplication] delegate]).enablePortrait= NO; 

в App Delegate.

 - (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { NSLog(@"Interface orientations"); if(!enablePortrait) return UIInterfaceOrientationMaskLandscape; return UIInterfaceOrientationMaskLandscape|UIInterfaceOrientationMaskPortrait; } 

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

Несколько лет назад был аналогичный вопрос с рядом ответов. Вот недавний ответ от кого-то на этот вопрос:
Есть ли документальный способ настройки ориентации iPhone?

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

На стороне примечания, у меня была аналогичная проблема некоторое время назад, когда я вызывал что-то в shouldAutorotate, и я добавил код для viewWillAppear чтобы попытаться его исправить. Я, честно говоря, не могу вспомнить, если это сработало, и у меня нет Mac, чтобы попробовать, но я нашел код, и я вставлю его здесь, если он даст какое-то вдохновение.

 - (void)viewWillAppear:(BOOL)animated{ UIInterfaceOrientation o; switch ([UIDevice currentDevice].orientation) { case UIDeviceOrientationPortrait: o = UIInterfaceOrientationPortrait; break; case UIDeviceOrientationLandscapeLeft: o = UIInterfaceOrientationLandscapeLeft; break; case UIDeviceOrientationLandscapeRight: o = UIInterfaceOrientationLandscapeRight; break; default: break; } [self shouldAutorotateToInterfaceOrientation:o]; } 

НЕ ИСПОЛЬЗУЙТЕ ЭТОТ ХАК, ЯБЛОК ОТКЛЮЧАЕТ ПРИЛОЖЕНИЕ, ОСНОВАННОЕ НА ИСПОЛЬЗОВАНИИ «ЧАСТНОГО API»,

Для справки, я оставлю здесь свой ответ, но использование частного API не пройдет мимо обзорной доски. Сегодня я чему-то научился: D Как @younce правильно цитировал документы Apple, то, что я хочу, не может быть достигнуто с помощью UINavigationController.

У меня было два варианта. Во-первых, я мог бы написать свой собственный controller навигационного controllerа со всеми ужасами, с которыми он столкнулся при этом. Во-вторых, я мог бы взломать поворот в controllerах представления, используя недокументированную функцию UIDevice, называемую setOrientation:animated:

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

 @interface UIDevice (UndocumentedFeatures) -(void)setOrientation:(UIInterfaceOrientation)orientation animated:(BOOL)animated; -(void)setOrientation:(UIInterfaceOrientation)orientation; @end 

Затем вам нужно проверить поддерживаемые ориентации на viewWillAppear: Рядом с используемыми здесь методами UIDevice вы также можете заставить портретную ориентацию представить модальный controller, но это произойдет мгновенно и не анимировано, так что это мой предпочтительный способ:

 -(void)viewWillAppear:(BOOL)animated { UIDevice *device = [UIDevice currentDevice]; UIDeviceOrientation realOrientation = device.orientation; if ([self shouldAutorotateToInterfaceOrientation:realOrientation]) { if (realOrientation != [UIApplication sharedApplication].statusBarOrientation) { // Resetting the orientation will trigger the application to rotate if ([device respondsToSelector:@selector(setOrientation:animated:)]) { [device setOrientation:realOrientation animated:animated]; } else { // Yes if Apple changes the implementation of this undocumented setter, // we're back to square one. } } } else if ([self shouldAutorotateToInterfaceOrientation:UIInterfaceOrientationPortrait]) { if ([device respondsToSelector:@selector(setOrientation:animated:)]) { // Then set the desired orientation [device setOrientation:UIDeviceOrientationPortrait animated:animated]; // And set the real orientation back, we don't want to truly mess with the iPhone's balance system. // Because the view does not rotate on this orientation, it won't influence the app visually. [device setOrientation:realOrientation animated:animated]; } } } 

Хитрость заключается в том, чтобы всегда поддерживать ориентацию внутреннего устройства в «реальной» ориентации устройства. Если вы начнете изменять это, rotation приложения будет вне баланса.

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

Cheers, EP.

В iOS 6 это стало очень простой проблемой. Просто создайте специальный class для просмотров, которые вы хотите авторотировать. Затем добавьте это в свой rootVC.

 -(BOOL)shouldAutorotate{ BOOL should = NO; NSLog(@"%@", [self.viewControllers[self.viewControllers.count-1] class]); if ([self.viewControllers[self.viewControllers.count-1] isKindOfClass:[YourAutorotatingClass class]]) { should = YES; } return should; } 

Я знаю, что это старый вопрос, но я подумал, что стоит упомянуть.

  • Как получить доступ к управлению текстовым полем Winform из другого classа?
  • Что такое разработка, основанная на компонентах?
  • Что и где находятся стек и куча?
  • Управление диаграммой MS с двумя Y-осями
  • Как выбрать правильную область бобов?
  • Переопределение общедоступных виртуальных функций с частными функциями в C ++
  • self.title устанавливает заголовок navigationController и tabBarItem? Зачем?
  • WPF TextBox и поведение прокрутки
  • Чтение 40-гигабайтного CSV-файла в R с использованием bigmemory
  • c: forEach внутри перьев (например, p: panelgrid) внутри ui: repeat
  • Лучший способ получить доступ к элементу управления в другой форме в Windows Forms?
  • Давайте будем гением компьютера.