Как обрабатывать разные ориентации в iOS
ДОБАВЛЕНО: Вы можете получить доступ к этому проекту на github ios6rotations
Извините, ребята, что задали вопрос о повороте экрана в iOS 6, но это действительно очень неприятно... и я до сих пор не могу понять это полностью - по некоторым причинам он ведет себя по-разному при определенных обстоятельствах.
У меня есть следующая простая иерархия представлений в моем тестовом приложении:
Я пытаюсь добиться того, чтобы синий контроллер оставался только в альбомной ориентации, а красный - только в портретной.
У меня есть подкласс UINavigationController с таким кодом внутри:
@implementation CustomNavController
- (BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
- (NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
@end
В моем синем контроллере я реализовал это:
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscape;
}
И в красном контроллере это:
- (BOOL)shouldAutorotate {
return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskPortrait;
}
Теперь у меня следующее поведение:
- Приложение запущено в пейзаже (ОК)
- Когда я нажимаю кнопку, мой красный контроллер также нажимается в альбомной ориентации (это не нормально, потому что это должно быть показано в книжной ориентации)
- Он успешно поворачивается к портрету, но не назад к ландшафту
- Если я оставляю красный контроллер в портретном режиме, мой синий контроллер (который ограничен альбомной ориентацией) отображается в портретном режиме.
PS Все мои методы ротации (опубликованные выше) вызываются нормально (кстати, почему эти методы вызываются так много раз за переход экрана - 5-6 раз)
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
не вызывается с нажатием
Все (кроме PortraitUpsideDown) ориентации включены в plist.
Вопрос в том, как заставить вращение для поддерживаемой ориентации в каждом контроллере?
Я предлагаю вам опубликовать здесь (в качестве ответов) любой 100% рабочий код для обработки поворотов в ios6 (например, если у вас есть некоторые для iPad с SplitController) - я оставлю этот вопрос в избранном, чтобы все было в одном месте, когда мне нужно справиться с некоторыми конкретными ситуациями. Ура!
ДОБАВЛЕНО: Пожалуйста, не публикуйте это как ответ из пейзажа в портрет. Я надеюсь, что есть более элегантный способ сделать это.
6 ответов
С помощью -[UIDevice setOrientation:]
является частным API, и ваше приложение будет отклонено. Смотрите этот вопрос.
То, что вы спрашиваете, невозможно с помощью общедоступного API и также не рекомендуется с точки зрения HIG. Что поддерживается и вам следует реализовать, так это модальное представление различных контроллеров представления с различной поддерживаемой ориентацией интерфейса. Вот почему реализация по умолчанию UINavigationController
это всегда вращаться; предполагается, что все контроллеры представления имеют одинаковую поддерживаемую ориентацию интерфейса.
Возьмите, например, воспроизведение видео на iPhone. Откройте видео приложения (которые поставляются с iOS). Контроллер корневого представления поддерживает только книжную ориентацию. Тем не менее, запустите видео, и появится модальный контроллер вида, который поддерживает только альбомную ориентацию интерфейса. Это похоже на поведение, которого вы хотите достичь.
Вот почему preferredInterfaceOrientationForPresentation
не называется. preferredInterfaceOrientationForPresentation
вызывается только при использовании presentViewController:animated:
,
Небольшое затруднение: если вам требуется панель навигации на каждом этапе вашей сцены, вам нужно будет заключить каждый контроллер модального представления в контроллер навигации. Затем вы можете передать необходимые данные в prepareForSegue:
путем доступа topViewController
объекта контроллера навигации в очереди.
Вот пример проекта, который ведет себя правильно в соответствии с вашими требованиями (или, по крайней мере, даст вам идеи, как его реализовать):
Мои два цента стоят.
Вы можете быстро представить пустой прозрачный модальный вид, а затем закрыть его, возможно, с помощью ViewDidLoad: или viewWillAppear: в вашем классе ViewController и ViewControllerSecond в качестве быстрого обходного пути.
Кроме того, в раскадровке вы можете визуально установить ориентацию класса ViewController.
У меня похожая ситуация в одном из моих приложений (хотя учтите, что я не использую UINavigationController).
Изменить shouldAutorotate
методы в обоих ваших viewControllers:
//in blue (landscape only)
-(BOOL)shouldAutorotate{
if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) {
return YES;
}
else {
return NO;
}
}
//in red (portrait only)
-(BOOL)shouldAutorotate{
if (self.interfaceOrientation == UIInterfaceOrientationPortrait) {
//note that UIInterfaceOrientationIsPortrait(self.interfaceOrientation) will return yes for UIInterfaceOrientationPortraitUpsideDown
return YES;
}
else {
return NO;
}
}
Держать supportedInterfaceOrientations
методы одинаковые.
Используйте эту строку для программного изменения ориентации... работа 100%
[[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeRight];
а также, когда вы добавляете эту строку в это время, появляется одно предупреждение, а для удаления этого предупреждения просто добавьте нижеприведенный код в ваш файл реализации... вверху.
@interface UIDevice (MyPrivateNameThatAppleWouldNeverUseGoesHere)
- (void) setOrientation:(UIInterfaceOrientation)orientation;
@end
и после этого в методе ниже просто напишите этот код, если требуется..
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return your supported orientations
if (currentMainView==blueOne) {
return toInterfaceOrientation== UIInterfaceOrientationPortrait;
}
}
#pragma mark- Orientation Delegate Method:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{ Orientation = [UIApplication sharedApplication].statusBarOrientation;
if (Orientation == UIInterfaceOrientationLandscapeLeft || Orientation == UIInterfaceOrientationLandscapeRight)
{
// self.scrollView.contentOffset = CGPointMake(self.view.bounds.size.width,1200);
[scrollView setScrollEnabled:YES];
[scrollView setContentSize:CGSizeMake(768, 2150)];
}else if (Orientation == UIInterfaceOrientationPortrait || Orientation == UIInterfaceOrientationPortraitUpsideDown)
{
[scrollView setScrollEnabled:YES];
[scrollView setContentSize:CGSizeMake(768, 1750)];
}
}
Чтобы использовать навигацию вместе с ориентацией, вы должны взять несколько контроллеров вида, таких как массив.
После этой проверки следующие методы,
-(BOOL)shouldAutorotate
{
return [[self.viewControllers lastObject] shouldAutorotate];
}
-(NSUInteger)supportedInterfaceOrientations
{
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}
эти изменения в ваших методах вам очень помогут.
Наслаждайтесь программированием!