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

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

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

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

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

 }

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

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

Спасибо!

4b9b3361

Ответ 1

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

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

Edit:

Я возвращаю YES для всех ориентаций в 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];
    }

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

Ответ 2

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

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

  • триггеры на WILL вращаются, а не СЛЕДУЕТ вращаться (ждет, пока анимация вращения начнется)
  • использует соглашение об именах Apple для файлов ландшафта и портрета (Default.png - Default-landscape.png, если вы хотите, чтобы Apple автоматически загружала альбомную версию)
  • перезагружает новый NIB
  • который сбрасывает значение self.view - это автоматически изменит отображение
  • а затем он вызывает 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];
    }
}

Ответ 3

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

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

Ответ 4

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

Переход от портрета к пейзажу:

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

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

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

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

Helper:

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