tabBarController и navigationControllers в ландшафтном режиме, эпизод II

У меня есть UITabBarController, и каждая вкладка обрабатывает другой UIViewController, который при необходимости помещает в стек новые контроллеры. На двух из этих вкладок мне нужна возможность при достижении определенного контроллера возможность повернуть iPhone и визуализировать вид в альбомном режиме. После долгой борьбы я обнаружил, что создание подкласса UITabBarController является обязательным для переопределения shouldAutorotateToInterfaceOrientation. Однако, если я просто верну YES в реализации, возникнет следующий нежелательный побочный эффект:

каждый контроллер на каждой вкладке автоматически переводится в альбомный режим при повороте iPhone.

Даже переопределение shouldAutorotateToInterfaceOrientation в каждом контроллере для возврата NO не работает: когда iPhone поворачивается, контроллер переводится в ландшафтный режим.

Я реализовал shouldAutorotateToInterfaceOrientation в подклассе UITabBarController следующим образом:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if([self selectedIndex] == 0 || [self selectedIndex] == 3)
        return YES;

    return NO;
}

Так что только две интересующие меня вкладки фактически поддерживают ландшафтный режим. Есть ли способ поддержать ландшафтный режим для конкретного контроллера в стеке конкретной вкладки?

Я безуспешно пробовал что-то вроде

(BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation {

if([self selectedIndex] == 0 || [self selectedIndex] == 3)
{   
   if ([[self selectedViewController] isKindOfClass: [landscapeModeViewController class]])
           return YES;
    }

     return NO;

}

Кроме того, я безуспешно пытался использовать метод делегата didSelectViewController. Любая помощь приветствуется. Спасибо.


person Massimo Cafaro    schedule 16.04.2009    source источник


Ответы (7)


Это сработало для меня:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    if(self.selectedIndex == 0 && [[[self.viewControllers objectAtIndex:0] visibleViewController] isKindOfClass:[MyViewController class]])
        return YES;
    else
        return NO;
}
person Rich Aston    schedule 21.04.2009
comment
Рич, спасибо тебе большое. Предлагаемое решение работает как шарм ;-) Эта проблема сводила меня с ума! Я не понимал, что правильный способ сделать это также требует одновременной проверки visibleViewController. Отличный ответ! - person Massimo Cafaro; 21.04.2009

Вот расширение UITabBarController, которое делегирует вызовы shouldAutorotateToInterfaceOrientation текущему выбранному дочернему контроллеру. Используя это расширение, вам больше не нужно создавать подклассы UITabBarController, и вы можете использовать shouldAutorotateToInterfaceOrientation в своих контроллерах, как и следовало ожидать.

UITabBarController + Autorotate.h:

#import <UIKit/UIKit.h>

@interface UITabBarController (Autorotate)
@end

UITabBarController + Autorotate.m:

#import "UITabBarController+Autorotate.h"

@implementation UITabBarController (Autorotate)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    UIViewController *controller = self.selectedViewController;
    if ([controller isKindOfClass:[UINavigationController class]])
        controller = [(UINavigationController *)controller visibleViewController];
    return [controller shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

@end
person Zargony    schedule 31.07.2009
comment
На самом деле это даже не обязательно. UITabBarController, похоже, делает что-то подобное, но соглашается только с ориентациями, которые поддерживает каждый контроллер каждой вкладки. - person Zargony; 31.07.2009
comment
Андреас, это были бы потрясающие новости! Но я не вижу этого в своем приложении. В моем случае, если я не перейду к контроллеру представления, запрос на ротацию никогда не будет выполнен. Как только я вставляю его, сначала запрашивается контроллер панели вкладок, а затем я могу перейти к VC. Если что-то мне не хватает, сообщите, пожалуйста! На самом деле, у меня все еще возникают проблемы, когда ВК находится в разделе «Еще» на панели вкладок. В этом случае контроллер панели вкладок даже не вызывается. :( - person Joe D'Andrea; 13.08.2009
comment
Я разместил свою сагу в новой ветке. is.gd/2emkj (перенаправляет обратно на stackoverflow.com) - person Joe D'Andrea; 13.08.2009

Я могу использовать это некоторое время (из контроллера панели вкладок моего приложения) без проблем:

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

Таким образом, в соответствующем VC мы сможем выполнить реальную проверку, в данном случае для просмотра фотогалереи (что еще?):

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

Вид моей галереи даже не находится на вершине стека для данного контроллера навигации. Его по-прежнему называют.

Увы, я только что обнаружил, что это не работает так хорошо, когда VC скрывается внутри MoreViewController (в отличие от четырех основных вкладок). В таком случае мою галерею VC никогда не называют. Я думаю, это потому, что VC, который я звонил все это время, на самом деле является контроллером навигации из выбранной вкладки, который затем передает вещи в соответствующий VC, в данном случае мою фотогалерею VC. Но с More VC все работает не так хорошо ... ааа, и оттуда все идет вниз по кругу. : \

Я пробовал использовать модификации Андреаса (см. В другом месте в этой ветке), но безрезультатно. Подсказки приветствуются!

person Joe D'Andrea    schedule 12.08.2009
comment
Ага! Когда я пытаюсь повернуть интерфейс и ТОЛЬКО когда я использую VC в More View Controller, я вижу это в моем журнале консоли: Использование двухэтапной анимации вращения. Чтобы использовать более плавную одностадийную анимацию, это приложение должно удалить реализации двухэтапных методов. Эмм ... флеш, я НЕ использую двухэтапную анимацию! То есть я не отвечаю на willAnimateSecondHalfOfRotationFromInterfaceOrientation: duration: вообще. По-видимому, есть контроллер представления More, и поэтому я никогда не получаю вызов willAnimateRotationToInterfaceOrientation: duration: ... :( - person Joe D'Andrea; 13.08.2009
comment
Фактически, если я попытаюсь найти версию SecondHalf ... я тоже не получу этого звонка. Хм ... - person Joe D'Andrea; 13.08.2009

Я столкнулся с теми же проблемами, что и вы, при работе с UITabBarController. Мне нужно было контролировать, какие UIViewController разрешено вращать, а какие нет. Моя основная проблема была с вкладкой БОЛЬШЕ. Я не хотел, чтобы какой-либо из UIViewController, включенных во вкладку MORE, вращался.

Мое решение заключалось в создании моего собственного UITabBarController, который я назвал MyTabBarController:

@interface MyTabBarController : UITabBarController <UITabBarDelegate> {

}

Затем я реализовал метод shouldAutorotateToInterfaceOrientation:

@implementation MyTabBarController

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
 UIViewController *controller = [self selectedViewController];

 if ((controller == [self moreNavigationController]) || ([self selectedIndex] == 4))
 {
  return interfaceOrientation == UIInterfaceOrientationPortrait;
 }

 return [controller shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}

@end

Мне нужно было узнать, выбрана ли вкладка БОЛЬШЕ. Это двухэтапный процесс; когда изначально выбрана вкладка MORE, API возвращает selectedIndex больше 4, поэтому мне нужно было сравнить выбранный контроллер с moreNavigationController.

Если UIViewController выбран на вкладке MORE, то selectedIndex, наконец, равен 4, но selectedController больше не является moreNavigationController, а выбран UIViewController.

if ((controller == [self moreNavigationController]) || ([self selectedIndex] == 4)) решает эту проблему.

Теперь, когда я запускаю свое приложение, мои UIViewControllers на вкладке MORE не поворачиваются. Я надеюсь, что это поможет другим разработчикам, столкнувшимся с теми же проблемами, что и я.

Эмилио

person Community    schedule 09.01.2010
comment
Спасибо. Мне пришлось реализовать это, потому что я создавал свой tabbarcontroller программно, и кажется, что он не смог найти метод shouldAutorotateToInterfaceOrientation, даже если он определен в том же контроллере просмотра или appdelegate. Мне пришлось это сделать, чтобы поддерживать изменение ориентации на iOS5, в iOS6 это не обязательно. - person estemendoza; 12.04.2013

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

Я поместил его в категорию UITabBarController. Надеюсь, это допустимо!

// call to method shouldAutorotate replaces call to method shouldAutorotateToInterfaceOrientation (deprecated)
-(BOOL)shouldAutorotate
{ // check whether selected view controller should autorotate    
  UIViewController *controller = self.selectedViewController;
  if ([controller isKindOfClass:[UINavigationController class]])
    { // in case it is a navigation controller: get visible view of that
      controller = [(UINavigationController *)controller visibleViewController];
    }
  return [controller shouldAutorotate];
}
person AOphagen    schedule 04.04.2013

Спасибо Спасибо спасибо. На то, чтобы понять, как это сделать, ушло 2 дня. Вот мой взгляд на всю вашу большую помощь, когда у вас есть tabBarController с navigationControllers.

- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) interfaceOrientation {

UIViewController *controller = self.selectedViewController;
if ([controller isKindOfClass:[UINavigationController class]])
    controller = [(UINavigationController *)controller visibleViewController];

if([controller isKindOfClass:[LOCviewcontroller class]])
    return YES;
else
    if([controller isKindOfClass:[personWebSiteView class]])
        return YES;
else return NO; 

}

Любая критика кода неофита всегда приветствуется ... jack

person jangelo42    schedule 04.08.2010

Можно ли создать подкласс UITabBarController (как предлагается в принятом ответе выше)?

Я понял, что Apple говорит что-то вроде «вы никогда не должны создавать подклассы UITabBarController или UINavigationController» - или я неправильно понял?

Так или иначе; Я нашел это руководство, где они создают подклассы UIViewController, в которые они помещают UITabBarController.

person Manne W    schedule 18.02.2011