Как обрабатывать разные ориентации в 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;
}

Теперь у меня следующее поведение:

  1. Приложение запущено в пейзаже (ОК)
  2. Когда я нажимаю кнопку, мой красный контроллер также нажимается в альбомной ориентации (это не нормально, потому что это должно быть показано в книжной ориентации)
  3. Он успешно поворачивается к портрету, но не назад к ландшафту
  4. Если я оставляю красный контроллер в портретном режиме, мой синий контроллер (который ограничен альбомной ориентацией) отображается в портретном режиме.

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 объекта контроллера навигации в очереди.


Вот пример проекта, который ведет себя правильно в соответствии с вашими требованиями (или, по крайней мере, даст вам идеи, как его реализовать):

http://www.mediafire.com/?zw3qesn8w4v66hy

Мои два цента стоят.

Вы можете быстро представить пустой прозрачный модальный вид, а затем закрыть его, возможно, с помощью 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];
}

эти изменения в ваших методах вам очень помогут.

Наслаждайтесь программированием!

Другие вопросы по тегам