Самый простой способ поддержки нескольких ориентаций? Как загрузить пользовательский NIB, когда приложение находится в альбомной ориентации? - PullRequest
35 голосов
/ 23 марта 2010

У меня есть приложение, в котором я хотел бы поддерживать несколько ориентаций.У меня есть два файла .xib, которые я хочу использовать: myViewController.xib и myViewControllerLandscape.xib. myViewController.xib существует в проекте / ресурсах, а myViewControllerLandscape.xib существует в корневом каталоге проекта.

Я хочу использовать отдельныйNIB (myViewControllerLandscape.xib) для моих вращений.Я пытаюсь обнаружить вращение в viewDidLoad l, например:

if((self.interfaceOrientation == UIInterfaceOrientationLandscapeLeft) || (self.interfaceOrientation == UIInterfaceOrientationLandscapeRight))
 {
  NSLog(@"Landscape detected!");
  [self initWithNibName:@"myViewControllerLandscape" bundle:nil];

 }

Но я вижу в GDB, что это не выполняется, когда приложение запускается с устройства в альбомной ориентации.Сообщение NSLog не срабатывает.Почему это?Что я сделал не так?

Кроме того, если я явно поместил вызов функции initWithNibName в метод viewDidLoad, этот кончик не загружается, и он продолжается с myViewController.xib файл.Что не так с моим звонком?Нужно ли указывать комплект?

Спасибо!

Ответы [ 5 ]

58 голосов
/ 10 мая 2012

Я нашел гораздо лучший способ, который работает независимо от контроллера навигации.Прямо сейчас у меня это работает, когда встроено в контроллер Nav, а когда НЕ встроено (хотя сейчас я не использую контроллер Nav, поэтому может быть какая-то ошибка, которую я не видел - например, анимация перехода PUSH может идтисмешно, или что-то в этом роде)

Два NIB с использованием соглашения Apple об именовании.Я подозреваю, что в iOS 6 или 7 Apple может добавить это как «функцию».Я использую его в своих приложениях, и он отлично работает:

  1. срабатывает при повороте WILL, НЕ ДОЛЖЕН вращаться (ждет, пока не начнется анимация поворота)
  2. использует AppleСоглашение об именах для альбомных / портретных файлов (Default.png - это Default-landscape.png, если вы хотите, чтобы Apple автоматически загружала альбомную версию)
  3. перезагружает новый NIB
  4. , который сбрасывает self.view - это автоматически обновит дисплей
  5. и затем вызовет viewDidLoad (Apple НЕ будет звонить вам, если вы вручную перезагрузите NIB)
-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    if( UIInterfaceOrientationIsLandscape(toInterfaceOrientation) )
    {
        [[NSBundle mainBundle] loadNibNamed: [NSString stringWithFormat:@"%@-landscape", NSStringFromClass([self class])]
                                      owner: self
                                    options: nil];
        [self viewDidLoad];
    }
    else
    {
        [[NSBundle mainBundle] loadNibNamed: [NSString stringWithFormat:@"%@", NSStringFromClass([self class])]
                                      owner: self
                                    options: nil];
        [self viewDidLoad];
    }
}
40 голосов
/ 23 марта 2010

Вы должны загрузить один вид, затем проверить ориентацию и загрузить другой, если это необходимо. Вы проверяете ориентацию в shouldAutorotateToInterfaceOrientation:, возвращая да, если хотите повернуть.

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

Edit:

Я возвращаю ДА для всех ориентаций в shouldAutorotateToInterfaceOrientation: но будет ли это вызываться, когда приложение катера? Вы выдвигаете свой взгляд изнутри? этой функции?

Константы ориентации - это не глобальные запросы, которые вы запрашиваете, а часть сообщений, отправляемых контроллером системой. Таким образом, вы не можете легко определить ориентацию до загрузки контроллера вида. Вместо этого вы проводите приложение в определенную ориентацию (обычно в портретной ориентации), а затем сразу же поворачиваетесь. (См. Мобильное Safari. Оно всегда начинается в портретной ориентации, а затем поворачивается в альбомную ориентацию.)

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

У всех трех контроллеров представления есть этот метод:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}

На портрете есть это:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {
        [self.nav pushViewController:rightLVC animated:NO];
    }
    if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
        [self.nav pushViewController:leftLVC animated:NO];
    }
}

У каждого контроллера ландшафта есть это:

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {

    if (toInterfaceOrientation==UIInterfaceOrientationPortrait) {
        [self.nav popViewControllerAnimated:NO];
    }

Приложение запускается в портретной ориентации. Если устройство ориентировано на пейзаж, оно выдвигает соответствующие ландшафты. Когда устройство поворачивается обратно в портретное положение, оно отображает пейзаж. Для пользователя это выглядит так же, как реорганизация себя для другой ориентации.

5 голосов
/ 03 марта 2013

Действительно как ответ Адама - я немного изменил его, чтобы учесть начальную загрузку пера в книжной или альбомной ориентации

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if( !nibNameOrNil )     nibNameOrNil = [self nibNameRotated:[[UIApplication sharedApplication] statusBarOrientation]];
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    return self;
}

- (NSString*) nibNameRotated:(UIInterfaceOrientation)orientation
{
    if( UIInterfaceOrientationIsLandscape(orientation))     return [NSString stringWithFormat:@"%@-landscape", NSStringFromClass([self class])];
    return [NSString stringWithFormat:@"%@", NSStringFromClass([self class])];
}

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    NSString *nibname = [self nibNameRotated:toInterfaceOrientation];
    [[NSBundle mainBundle] loadNibNamed:nibname owner:self options:nil];
    [self viewDidLoad];
}
1 голос
/ 31 июля 2013

Еще один выбор, TPMultiLayoutViewController .

1 голос
/ 29 марта 2012

Мне нравится принятый ответ TechZen, но, как указано в комментарии Адама, он оставляет контроллер портретного представления в стеке навигации при повороте на альбомную ориентацию. Это означает, что нажатие кнопки «Назад» на панели навигации в горизонтальной ориентации переведет пользователя в портретный режим. Мы с коллегой пытаемся вручную удалить лишний предмет из стека навигации. Кажется, это работает, но у меня пока очень мало опыта, поэтому я не даю никаких обещаний. Вот пример кода:

Чтобы перейти от портрета к пейзажу:

[[self navigationController] pushViewController:landscapeViewController animated:NO];
[self removeFromNavigationStack:[MyPortraitViewController class]];

Чтобы вернуться к портрету:

[[self navigationController] pushViewController:portraitViewController animated:NO];
[self removeFromNavigationStack:[MyLandscapeViewController class]];

Если вы не используете анимацию: НЕТ, вы можете получать предупреждения о состоянии навигации.

Помощник:

- (void)removeFromNavigationStack:(Class)oldClass {
      UINavigationController *nav = [self navigationController];
      NSMutableArray *newStack = [NSMutableArray array];
      for (UIViewController *vc in nav.viewControllers) {
          if (![vc isMemberOfClass:[oldClass class]]) {
              [newStack addObject: vc];            
          }
      [nav setViewControllers:newStack animated:NO];
  }
...