2009-06-09 3 views
24

У меня есть UIViewController, который возвращает YES в shouldAutorotateToInterfaceOrientation: для UIDeviceOrientationPortrait и NO для всего остального. С этим видом в верхней части стека я использую pushViewController:animated:, чтобы нажать новый UIViewController. Новый контроллер возвращает YES для чего-либо в shouldAutorotateToInterfaceOrientation:.UINavigationController and autorotation

Первый вид отказывается вращаться (как и ожидалось). Как только второе представление будет нажато, пользователь может повернуть устройство, и пользовательский интерфейс будет вращаться (также как и ожидалось). Если второе изображение находится в ландшафтном режиме, и пользователь нажимает кнопку «Назад» (который вызывает popViewControllerAnimated:), первое изображение будет повернуто (неожиданно!).

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

Единственным обходным решением, которое я нашел до сих пор, является использование -[UIDevice setOrientation:], которое выдает предупреждение (orientation доступно только для чтения), но работает, поскольку оно фактически определено. Это огромный взлом, и я бы хотел найти реальное решение. В поисках реального решения я приложил GDB к приложению «Фотографии» (MobileSlideshow.app) и обнаружил, что он также использует -[UIDevice setOrientation:]. Будучи внутренним приложением, хотя, я думаю, у них разные правила.

Есть ли правильный способ достижения ожидаемого поведения авторотации?

+0

Я считаю, что есть примеры приложений, которые (предположительно) используют setOrientation в магазине приложений. Одним из них является Tweetie, который может заставить пейзажную клавиатуру при написании твитов. Возможно, им это удалось, поскольку это не настройки по умолчанию. –

+0

Сейчас 2014 год, и эта проблема все еще встречается на ios 8. Кто-нибудь нашел реальный ответ на эту проблему, но это не похоже на взлом? –

ответ

1

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

Вам нужно будет исправить дочерний контроллер навигации, чтобы иметь правильную кнопку возврата. И, конечно же, вам придется обращаться к кнопке «Назад». Вам, вероятно, придется использовать манекен UINavigationBar, чтобы сделать анимацию от одного контроллера навигации до следующего, чтобы переход выглядел правильно. Вам также нужно будет анимировать переход «push» между навигационными контроллерами, что может потребовать немного настройки, чтобы заставить его выглядеть правильно. Вы должны были бы:

  1. Настройте панель манекена, чтобы точно соответствовать контроллеру исходящей навигации, и поместите его непосредственно над панелью навигационного контроллера. (Вы можете скопировать конфигурацию тока контроллера вида UINavigationItem и толкать его на)
  2. Поместите новый навигационный контроллер вне экрана на правом крае
  3. анимировать движение кадров новых и старых контроллеров справа налево
  4. Создать копию UINavigationItem для входящего контроллера представления и толкать его на манекене панели навигации
  5. Когда анимация закончится, удалите фиктивный UINavigationBar с точки зрения, а также исходящий навигационный контроллер.

Все это очень много работы, но если вы очень умны (и очень цепкие), вы можете заставить его работать. Я бы хотел увидеть результат!

Тем не менее, вы могли бы быть лучше просто использовать setOrientation: и принимая ваши шансы с процессом утверждения App Store ;-)

1

Попробуйте снова с OS 3.0 (теперь, когда мы можем говорить об этом). Два специальных случая этого были разработаны в соответствии с 3.0:

  1. Представление портретного вида на вид на пейзаж и наоборот. Примером является поведение pre-3.0 в Mail для просмотра вложений. Вы можете повернуть в альбомную область для PDF-файла и вернуть портретный вид сообщения, когда вы отклонили представление вложения. (Теперь, когда у нас есть представление о ландшафтных сообщениях в 3.0, это поведение, похоже, исчезло).

  2. Смешивание ориентации в стеке просмотра и получение правильной ориентации назад при появлении стека. Примером может служить переход между просмотром фильмов и просмотром видео в приложении YouTube.

Похоже, что были некоторые острые эстетические проблемы того, как должны выглядеть переходы по умолчанию для всех перестановок. Есть некоторые странные элементы, если вы смотрите в slo-mo, но он бьет в обратном направлении в свой собственный код.

+0

Я пробовал это, и # 1, похоже, работает правильно, но # 2 не работает для меня. Я создал проект nav-controller с контроллерами табличных представлений. Корневой вид не может вращаться, но нажатый вид может. Когда вы откроете второй вид, он будет вращаться. Фактически, элементы nav-bar, похоже, запутались, показывая название второго представления даже после того, как он выскочил. –

0

Так это раздражает ошибка приходит очень долгий путь от 1 до прошивки прошивки 4.

Я считаю, что самое лучшим решением, мы должны его дублировать this bug и пусть Apple, знает, что мы на самом деле хотим ее исправить. Я только что сообщил об этом снова под идентификатором ошибки 8478525.

5

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

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

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

Решение: Убийца должен запретить вращение на viewWillAppear и представить & увольнение modalViewController без анимации.

  1. appViewController добавляется к окну в качестве хозяина ViewController, т.е.rooter, чем RootViewController;
  2. В appViewController добавлен навигационный контроллер, с делегат установлен в appViewController;
  3. В AppViewController


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    if (interfaceOrientation == UIInterfaceOrientationPortrait) return YES; 
    return canRotate; 
} 


- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated 
{ 
    [viewController viewDidAppear:animated]; 
    canRotate = ([navigationController.topViewController isKindOfClass:[MyRotatable class]]); 
} 


- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated 
{ 
    [viewController viewWillAppear:animated]; 
    if (![navigationController.topViewController isKindOfClass:[MyRotatable class]]) { 
     canRotate = NO; 
     UIViewController * blanck = [[UIViewController alloc] initWithNibName:nil bundle:nil]; 
     [self presentModalViewController:blanck animated:NO]; 
     [self dismissModalViewControllerAnimated:NO]; 
     [blanck release]; 
    } 
} 
6

правовая альтернатива UIDevice setOrientation выглядит следующим образом:

UIWindow* window = UIApplication.sharedApplication.keyWindow; 
UIView* view = [window.subviews objectAtIndex:0]; 
[view removeFromSuperview]; 
[window addSubview:view]; 

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

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

- (void)popBack 
{ 
    [self.navigationController popToRootViewControllerAnimated:YES]; 
} 

- (IBAction)backPressed:(id)sender 
{ 
    portraitOrientationPermitted = NO; 

    // Force the framework to re-evaluate the interface orientation. 
    UIWindow* window = UIApplication.sharedApplication.keyWindow; 
    UIView* view = [window.subviews objectAtIndex:0]; 
    [view removeFromSuperview]; 
    [window addSubview:view]; 

    [self performSelector:@selector(popBack) withObject:nil afterDelay:0.8]; 

    portraitOrientationPermitted = YES; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return portraitOrientationPermitted || 
     UIInterfaceOrientationIsLandscape(interfaceOrientation); 
} 
+0

Грязный грязный рубить, но он работает. – beefon

+2

Не работает для меня на iOS 7. Однако удаление окна rootViewController и его повторное включение было выполнено. Просто поставьте это на случай, если кто-то столкнется с той же проблемой. – entropy

1

Я нашел хороший способ решения проблемы. Подсказка должна поддерживать все ориентации для все Просмотров в UINavigationController.

У меня есть 2 вида в контроллере. Корневой вид поддерживает только LandscapeRight, а второй поддерживает как LandscapeRight, так и Portrait.

Второй метод вид shouldAutorotateToInterfaceOrientation выглядит как обычно:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) || 
      (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 

Сам обходной путь содержится в источнике вид Root Теперь вид корень вращается с точки зрения кода, но пользователь не могу видеть его.

//auxiliary function 
-(void) fixOrientation:(UIInterfaceOrientation)orientation 
{ 
    if (orientation == UIInterfaceOrientationPortrait) 
     self.view.transform = CGAffineTransformMakeRotation(M_PI_2); 
    else if (orientation == UIInterfaceOrientationLandscapeRight) 
     self.view.transform = CGAffineTransformMakeRotation(0); 
} 

-(void) viewWillAppear:(BOOL)animated 
{ 
    [self fixOrientation:[[UIApplication sharedApplication] statusBarOrientation]]; 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 
{ 
    [self fixOrientation:interfaceOrientation]; 
    //notice, that both orientations are accepted 
    return (interfaceOrientation == UIInterfaceOrientationLandscapeRight) || 
      (interfaceOrientation == UIInterfaceOrientationPortrait); 
} 

//these two functions helps to avoid blinking 
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    [UIView setAnimationsEnabled:NO]; // disable animations temporarily 

} 

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation 
{ 
    [UIView setAnimationsEnabled:YES]; // rotation finished, re-enable them 
} 
4

IOS 5 добавляет + [UIViewController attemptRotationToDeviceOrientation], который решает эту проблему для меня.

+1

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

Смежные вопросы