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

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

каждый контроллер на каждой вкладке автоматически помещается в альбомный режим при повороте 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 без успеха. Любая помощь приветствуется. Спасибо.

Ответ 1

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

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    if(self.selectedIndex == 0 && [[[self.viewControllers objectAtIndex:0] visibleViewController] isKindOfClass:[MyViewController class]])
        return YES;
    else
        return NO;
}

Ответ 2

Здесь добавляется расширение 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

Ответ 3

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

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

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

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

Моя галерея не даже находится в верхней части стека для данного контроллера Nav. Он по-прежнему вызван.

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

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

Ответ 4

Я столкнулся с теми же проблемами, что и при работе с UITabBarController. Мне нужно было контролировать, какие UIViewControllers были разрешены для вращения, а какие нет. Моя основная проблема заключалась в закладке MORE. Я не хотел, чтобы любой из UIViewControllers, включенных в вкладку 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. Это двухэтапный процесс; когда сначала выбирается вкладка MORE, API возвращает selectIndex выше 4, поэтому мне нужно сравнить выбранный контроллер с moreNavigationController.

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

if ((controller == [self moreNavigationController]) || ([self selectedIndex] == 4)) заботится об этой проблеме.

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

Эмилио

Ответ 5

Из того, что я видел здесь и в других местах, я сшил решение, использующее метод 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];
}

Ответ 6

Спасибо, спасибо, спасибо. Это было 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

Ответ 7

Действительно ли это нормально для подкласса UITabBarController (как указано в принятом ответе выше)?

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

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