Как ограничить автоповорот одной ориентацией для одних видов, допуская при этом все ориентации для других? - PullRequest
30 голосов
/ 17 февраля 2011

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

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

Настройка очень проста: три контроллера вида называются FirstViewController, SecondViewController иThirdViewController все расширяют AbstractViewController, который показывает метку с именем класса и которая возвращает ДА ​​для shouldAutorotateToInterfaceOrientation:, когда устройство находится в портретной ориентации.SecondViewController переопределяет метод this, чтобы обеспечить все повороты.Все три конкретных класса добавляют несколько цветных квадратов, чтобы можно было перемещаться между представлениями, нажимая и вставляя контроллеры в / 10 *.Пока что очень простой сценарий, я бы сказал.

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

Expected view orientation for the device in portrait mode Expected view orientation for the device in landscape mode

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

Actual view orientation for the device in landscape mode

У меня вопрос двоякий:

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

Cheers, EP.

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

Ответы [ 5 ]

8 голосов
/ 22 февраля 2011

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

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

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

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

Подробнее о о проблемах вращения читайте здесь .

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

5 голосов
/ 04 декабря 2012

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

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

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

в приложении Delegate.

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

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

4 голосов
/ 20 февраля 2011

Несколько лет назад был похожий вопрос с несколькими ответами. Вот недавний ответ от кого-то на этот вопрос:
Есть ли документированный способ установки ориентации 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];
}
2 голосов
/ 11 февраля 2013

В iOS 6 это стало очень простой проблемой.Просто создайте специальный класс для представлений, которые вы хотите автоматически изменить.Затем добавьте это в свой 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;
}

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

2 голосов
/ 20 февраля 2011

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

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

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

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

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

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

-(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];
        }
    }
}

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

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

Cheers, EP.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...