Подтвердить что ты не робот

ShouldAutorotateToInterfaceOrientation не вызывается в iOS 6

Я использую MGSplitViewController, и я использую shouldAutorotateToInterfaceOrientation для управления размером контроллера главного представления при вращении.

Все работает отлично на iOS 5, но на iOS 6 (как симулятор, так и iPad) shouldAutorotateToInterfaceOrientation никогда не вызывается.

Является ли это ошибкой, которую я должен ожидать исправления с окончательной версией iOS 6 или что-то, о чем я не знаю, изменилось?

4b9b3361

Ответ 1

ПОЖАЛУЙСТА, ПРОЧИТАЙТЕ это ВНИМАТЕЛЬНО, или вы можете потерять 1-2 дня своей жизни, сойдя с ума и сражаясь, встряхивая, превращая ваше тестовое устройство, как шимпанзе в зоопарк, который схватил посетителя мобильного! Рано или поздно... обещание:)

IN iOS 6

shouldAutorotateToInterfaceOrientation:

устарел и заменен на

shouldAutorotate

это означает, что iOS 6 никогда не вызовет shouldAutorotateToInterfaceOrientation:

поэтому, если вы использовали следующее в своем приложении

ПЕРЕД iOS6 (iOS5, iOS4 и т.д.)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if (interfaceOrientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

вы должны использовать

ПОСЛЕ iOS 6 +

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];

if (orientation == UIInterfaceOrientationPortrait) {
// your code for portrait mode

}

return YES;
}

ОЗНАКОМИТЬСЯ

UIInterfaceOrientation является свойством UIApplication и содержит только 4 возможности, которые соответствуют ориентации строки состояния:

UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,

UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,

UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,

UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft

НЕ СОХРАНЯЙТЕСЬ с

UIDeviceOrientation, который является свойством класса UIDevice и содержит 7 возможных значений:

UIDeviceOrientationUnknown - Can not be determined

UIDeviceOrientationPortrait - Home button facing down

UIDeviceOrientationPortraitUpsideDown - Home button facing up

UIDeviceOrientationLandscapeLeft - Home button facing right

UIDeviceOrientationLandscapeRight - Home button facing left

UIDeviceOrientationFaceUp - Device is flat, with screen facing up

UIDeviceOrientationFaceDown - Device is flat, with screen facing down

даже теоретически можно использовать UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];, который возвращает UIDeviceOrientation - фактическую ориентацию устройства - НО вы должны знать, что UIDeviceOrientation не всегда равно UIInterfaceOrientation!!! Например, когда ваше устройство находится на простой таблице, вы можете получить неожиданное значение.

Вы можете использовать UIInterfaceOrientation orientation = self.interfaceOrientation;, который возвращает UIInterfaceOrientation, текущую ориентацию интерфейса, НО это свойство UIViewController, поэтому вы можете получить доступ к этому только в UIViewController классы.

Если вы хотите поддерживать как предыдущие устройства iOS6 (iOS3/4/5), так и iOS6, что может быть очевидным, просто используйте как shouldAutorotateToInterfaceOrientation:, так и shouldAutorotate в своем коде.

Из iOS 6 существует 3 уровня и 3 шага, которые устройство проверяет во время запуска приложения, которое вы должны контролировать, если хотите.

1. Info.plist - Supported Interface Orientations

который вы можете установить графически на вкладке "Сводка". Последовательность разрешенных ориентаций ВАЖНО, которую вы можете изменить вручную, отредактировав info.plist, и устройство выберет первое, когда приложение запустится! Это очень важно, поскольку проблема всегда заключается в запуске приложения, когда есть вероятность, что [UIDevice currentDevice].orientation неизвестен, особенно когда мы тестируем наше приложение на плоской поверхности.

plist setting in XCode (Info)

ОГРАНИЧИТЬ Существует еще две возможности настройки с расширением (iPad) или (iPhone), если вы используете какой-либо из них, он будет использовать эту настройку текущего устройства или симулятора и пренебречь общими настройками без расширения. Поэтому, если вы запустите приложение для iPhone только для iPhone, и случайно вы оставите строку "Поддерживаемые интерфейсы (iPad)" где-то в plist даже без каких-либо данных, она будет пренебрегать правилами, которые вы установили ранее в общих настройках (в моем примере для iPhone), и вы можете получить отказ от своего приложения с текстом "Мы обнаружили, что ваше приложение не соответствует требованиям для работы на iPad...", даже если ваше приложение не намерено использовать данную ориентацию на iPhone, но iPad будет использовать его, что может привести к непредсказуемым ошибкам, поскольку все приложения для iPhone должны запускаться на iPad тоже во время процесса отправки.

2. AppDelegate - application:supportedInterfaceOrientationsForWindow

возвращает список мини-масок всех разрешений, которые вы хотите разрешить, которые переопределяют параметры info.plist. Это называется по крайней мере один раз каждый раз, когда устройство вращается.

3. Top-level view controller or RootViewController - supportedInterfaceOrientations

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

shouldAutorotate

который препятствует разрешению приложения, и дает BOOL по умолчанию YES.

BE CAREFUL when you use `NavigationController`

как самый верхний контроллер в вашем AppDelegate, например:

DetailViewController *detailViewController = [[DetailViewController alloc] initWithNibName:@"DetailViewController" bundle:nil];
UINavigationController *navigationController=[[UINavigationController alloc] initWithRootViewController:detailViewController];
self.window.rootViewController =nil;
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;

в этом случае вы должны поместить следующий код в свой AppDelegate как вложение категории в класс NavigationController, так как это самый верхний контроллер, и если вы не сделали его подкатегории, у вас нет место/код, где вы можете установить свои настройки ориентации, поэтому вам нужно заставить его проверить ваш реальный rootViewController в этом случае detailViewController для ориентации:

@implementation UINavigationController (OrientationSettings_IOS6)

-(BOOL)shouldAutorotate {
return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations {
return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

после этого вы можете установить предпочтительные ориентации в своем "верхнем" ViewController (в моем примере это detailViewController) с любым из методов, доступных в iOS 6 для ViewControllers, как показано ниже:

1. (BOOL)shouldAutorotate

2. (NSUInteger)supportedInterfaceOrientations

3. (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

Ответ 2

Хорошо, я получил его для работы в iOS6 iPad Simulator. Ура. Вот что я сделал:

Я просто покажу вам до и после, он должен быть понятным:

перед

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

if (interfaceOrientation==UIInterfaceOrientationPortrait) {
 // do some sh!t

}

return YES;
}

после

- (BOOL)shouldAutorotate {

UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

if (orientation==UIInterfaceOrientationPortrait) {
 // do some sh!t

}

return YES;
}

Что касается поддерживаемой ориентации, вы можете указать в info.plist как таковой: Supported Orientation pic

Или используйте код:

-(NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait; // etc
}

Изменить: если подумать, если вы планируете поддерживать более низкие версии (iOS4.3/5/5.1), а также 6.0, то просто включите оба метода с тем же содержимым кода. Работает для меня (в любом случае в sim).

Ответ 3

Настройка контроллера маршрута окна приложения, а не просто добавление его в качестве подвью для меня (как это сделал Рокотилос)

//    [self.window addSubview:self.topLevelNavigationController.view];
self.window.rootViewController = self.topLevelNavigationController;

Ответ 4

Вот решение для iOS 5 и более раннего кода, которое не включает дублирование вашей логики. Просто добавьте этот код в свой контроллер просмотра и он генерирует поддерживаемые элементы интерфейса из существующего метода toAutorotateToInterfaceOrientation.

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{
NSInteger mask = 0;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeRight])
    mask |= UIInterfaceOrientationMaskLandscapeRight;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationLandscapeLeft])
    mask |= UIInterfaceOrientationMaskLandscapeLeft;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortrait])
    mask |= UIInterfaceOrientationMaskPortrait;
if ([self shouldAutorotateToInterfaceOrientation: UIInterfaceOrientationPortraitUpsideDown])
    mask |= UIInterfaceOrientationMaskPortraitUpsideDown;
return mask;
}

Ответ 5

Быстрое решение для меня заключалось в том, чтобы добавить этот код в свой контроллер корневого представления

- (BOOL)shouldAutorotate {
    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

Таким образом, я по-прежнему использую ту же логику, которая использовалась для версий до iOS 6. Конечно, я изначально установил мой rootViewController в своих делегатах приложения didFinishLaunchingWithOptions правильно, вместо того, чтобы просто добавлять к окнам subviews.

Ответ 6

И в то время как в ряде ответов указано решение - что для реализации shouldAutorotate и supportedInterfaceOrientations для сборки iOS 6 вы также должны знать, что если ваш контроллер представления размещен в контроллере навигации, то ни один из них не будет поскольку среда выполнения вызовет их в экземпляре UINavigationController и в противном случае игнорирует ваш код.

По-видимому, "решение" относится к подклассу UINavigationController и реализует эти новые методы в этом подклассе, как описано здесь: iOS 6 UITabBarController поддерживает ориентацию с текущим контроллером UINavigation

И тогда у вас есть удовольствие изменить весь ваш код, где вы используете UINavigationController для использования этого нового подкласса.

Это должно быть одним из самых бессмысленных и раздражающих изменений в релизе iOS, которые я когда-либо видел.

Ответ 7

IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
if (UIInterfaceOrientationLandscapeLeft) {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
    }
    if (UIInterfaceOrientationLandscapeRight) {
        return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
    }
    return (interfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations:(UIWindow *)window{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2


    //    return UIInterfaceOrientationMaskLandscape;
    return 24;
}

Ответ 8

Это сработало для меня с iOS6 и Xcode 4.5 GM:

В AppDelegate.m

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    .....

    //   self.window.rootViewController = self.navigationController;

    [window setRootViewController:navigationController];

    .....

    return YES;
}

на ViewController:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration

{
    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))

    {
      // landscape
    }
    else
    {
      //portrait
    }
}

Ответ 9

В ответ на @Rocotilos у меня есть добавление, которое произошло в моем коде, которое я не видел в других форумах. Я столкнулся с ситуацией, когда в самом начале жизненного цикла приложения, где ориентация не была известна в методе shouldAutorotate. Это заставило приложение не отображать представление в ландшафте. После нескольких поворотов в симуляторе он работал нормально.

Мой сценарий заключается в том, что есть определенные виды, которые появляются, когда мы хотим ландшафтного макета. Таким образом, мы бы не хотели, чтобы theAutorotate вернул ДА. Я понимаю, что это может быть редким случаем для некоторых, но я потратил много времени на диагностику этого и хотел пройти. Надеюсь, что это будет полезно.

- (BOOL) shouldAutorotate {

    BOOL shouldRotate = NO;
    UIInterfaceOrientation orientation = [[UIDevice currentDevice] orientation];

    if ([self IsCaseWhereWeDontWantLandscapeAutorotation]) {
        shouldRotate = NO;
    } else if (orientation == UIDeviceOrientationUnknown) {
        //Handle the case where the device orientation is not yet known
        shouldRotate = YES;
    } else {
        //Handle the normal case
        shouldRotate = (orientation == UIInterfaceOrientationMaskLandscape);
    }

    return shouldRotate;
}

Ответ 10

Оказывается, что обработчики этих вызовов обрабатываются только корневым представлением. В моем случае это был обычный UINavigationController. Мне пришлось изменить это на файл подкласса, где я добавил методы.

В моем случае мне нужен только портрет корневого представления, а остальное портрет + пейзаж.

Appdelegate.h

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    // Override point for customization after application launch.
    S2MBookAppRootViewController *masterViewController = [[[S2MBookAppRootViewController alloc] initWithNibName:pref.rootNibName bundle:nil] autorelease];
    self.navigationController = [[[S2MBookAppNavController alloc] initWithRootViewController:masterViewController] autorelease];

    self.window.rootViewController = self.navigationController;


    [self.window makeKeyAndVisible];
    [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleBlackOpaque animated:YES];

    return YES;
}

И S2MBookAppNavController (подкласс UINavigationController)

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    if([self.viewControllers count] == 1) return UIInterfaceOrientationMaskPortrait;
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape;
}

UPDATE: Если вы хотите принудительно настроить ориентацию (при нажатии нового вида на навигационном контроллере), попробуйте это.

Сделайте свой UINavigationController также своим собственным делегатом:

@interface S2MBookAppNavController : UINavigationController <UINavigationControllerDelegate>

@end

И в файле .m

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.delegate = self;
    // Do any additional setup after loading the view.
}

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
        if ([UIViewController respondsToSelector:@selector(attemptRotationToDeviceOrientation)]) {
            //present/dismiss viewcontroller in order to activate rotating.
            UIViewController *mVC = [[[UIViewController alloc] init] autorelease];
            [self presentModalViewController:mVC animated:NO];
            [self dismissModalViewControllerAnimated:NO];
        }
}

Ответ 11

Да, проблема заключается только в вызове метода window.rootViewController для возврата маски ориентации. Поэтому метод supportedInterfaceOrientations должен быть реализован в viewController, который установлен как window.rootViewController. Но в большинстве случаев этот объект не является обычным классом, например. UINavigationController. Одним из возможных решений является подкласс UINavigationController. Но Apple говорит: "Этот класс не предназначен для подкласса", поэтому я предпочел использовать другой UIViewController для обработки ориентации и добавил UINavigationController в качестве дочернего.

MyRootViewController * myRoot = [MyRootViewController new];
self.window.rootViewController = myRoot;
[myRoot addChildViewController:navigationController];
[myRoot.view addSubview:navigationController.view];

и в методах реализации MyRootViewController:

- (BOOL)shouldAutorotate {
 return YES;
}

- (NSUInteger)supportedInterfaceOrientations
{
    // return your mask here e.g.:
    return UIInterfaceOrientationMaskPortrait;
}

Ответ 12

Здесь приведена цитата из Apple iOS SDK, XCode4.5 + (см. Справочник класса UIViewController, Обработка поворотов просмотра):

В iOS 6 ваше приложение поддерживает ориентацию интерфейса, определенную в вашем файле Info.plist приложений. Контроллер вида может переопределить метод supportedInterfaceOrientations, чтобы ограничить список поддерживаемых ориентаций. Как правило, система вызывает этот метод только на контроллере корневого представления окна или контроллер представления, представленный для заполнения всего экрана; контроллеры дочерних представлений используют часть окна, предоставленную для них контроллером их родительского представления, и больше не участвуют непосредственно в решениях о том, какие вращения поддерживаются.

Также в iOS6 метод shouldAutorotateToInterfaceOrientation: класса UIViewController уже устарел.

Итак, в контроллере корневого представления вы выполните ff:

- (BOOL)shouldAutorotate {
  return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
  return UIInterfaceOrientationMaskPortrait;
}

Btw, "контроллер корневого представления" - это любой подкласс UIViewController, который вы устанавливаете как rootViewController вашего объекта appDelegate . Обычно вы делаете это в приложении appDelegate : метод didFinishLaunchingWithOptions:.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
  // Override point for customization after application launch.
  self.window.rootViewController = [FFDashboardController create];
  [self.window makeKeyAndVisible];
  return YES;
}

Что касается использования UINavigationController в качестве корневого VC, то выходите Vladimir answer.

Ответ 13

Заметки под заголовком UIKit здесь: http://developer.apple.com/library/ios/#releasenotes/General/RN-iOSSDK-6_0/_index.html%23//apple_ref/doc/uid/TP40012166-CH1-SW19 дают некоторые подсказки для ответа, но это не вся картина. У меня пока нет полной картины, но вот что я нашел до сих пор для RTM для iOS 6.0.

Если вы на самом деле не ограничиваете поддерживаемые ориентации и вместо этого вы хотите что-то сделать, потому что пользователь повернул устройство, тогда вы можете переместить логику в

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

к

- (void)viewWillLayoutSubviews

вместо.

Возможно, это будет прямая замена, но я еще не тестировал версии iOS на уровне ниже.

Если вы хотите ограничить поддерживаемые ориентации, вы должны сделать это на уровне UIApplicationDelegate с помощью

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window

В документации указано, что "Система определяет, поддерживается ли ориентация, пересекая значение, возвращаемое методом apps supportedInterfaceOrientationsForWindow:, со значением, возвращаемым методом supportedInterfaceOrientations самого верхнего полноэкранного контроллера". но в экспериментах я обнаружил, что система игнорирует поддерживаемые мои контроллеры просмотра

-(NSUInteger)supportedInterfaceOrientations

хотя метод вызывается.

Ответ 14

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

- (NSUInteger)supportedInterfaceOrientations{
   return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

Это гарантирует, что верхний контроллер будет определять ориентацию.

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

- (NSUInteger)supportedInterfaceOrientations{
   if(UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation]))       
      return UIInterfaceOrientationMaskPortrait;
   else
      return UIInterfaceOrientationMaskLandscape;
}

Ответ 15

-(BOOL)shouldAutorotate
{
    UIDeviceOrientation orientation = [UIDevice currentDevice].orientation;

    if (orientation == UIDeviceOrientationUnknown) {
        return YES;
    }

    return [self shouldAutorotateToInterfaceOrientation:self.interfaceOrientation];
}

Ответ 16

Apple использует устаревший метод toautorate от ios6, используя вместо этого эти методы. См. Ваши документы xcode

- (BOOL)shouldAutorotate NS_AVAILABLE_IOS(6_0);
- (NSUInteger)supportedInterfaceOrientations NS_AVAILABLE_IOS(6_0);
// Returns interface orientation masks.
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation NS_AVAILABLE_IOS(6_0);

Ответ 17

Его Работа для меня:

- (BOOL)shouldAutorotate {
    return YES;
}

- (NSUInteger)supportedInterfaceOrientations {
    NSUInteger orientations = UIInterfaceOrientationMaskPortrait;
    if ([self isKindOfClass:[YourViewController class]]) { // Your view class
        orientations |= UIInterfaceOrientationMaskPortraitUpsideDown;
    }
    return orientations;
}

ориентации:

orientations |= UIInterfaceOrientationMaskLandscapeLeft;
orientations |= UIInterfaceOrientationMaskLandscapeRight;