Как заставить UIViewController использовать портретную ориентацию в iOS 6

85

Поскольку ShouldAutorotateToInterfaceOrientationв iOS 6 эта функция устарела, и я использовал ее для принудительного отображения только портретной ориентации в конкретном представлении , как правильно это сделать в iOS 6? Это только для одной области моего приложения, все остальные представления могут вращаться.

Нил
источник

Ответы:

117

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

@implementation UINavigationController (Rotation_IOS6)

-(BOOL)shouldAutorotate
{
    return [[self.viewControllers lastObject] shouldAutorotate];
}

-(NSUInteger)supportedInterfaceOrientations
{
    return [[self.viewControllers lastObject] supportedInterfaceOrientations];
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return [[self.viewControllers lastObject] preferredInterfaceOrientationForPresentation];
}

@end

Как указано в некоторых комментариях, это быстрое решение проблемы. Лучшее решение - создать подкласс UINavigationController и поместить туда эти методы. Подкласс также помогает поддерживать 6 и 7.

Энтони
источник
3
Я могу подтвердить, что это работает. Вы также можете заменить «[self.viewControllers lastObject]» на «self.topViewController», если хотите.
Уэйн Лю
3
Если вы используете UITabBarController, эта категория UINavigationController не поможет. Вместо этого вы должны сделать категорию в UITabBarController ...
Борут Томазин
46
Проблема с этим решением заключается в том, что оно не работает, когда вы открываете контроллер, который был в альбомной ориентации, а ваш новый верхний контроллер поддерживает только портрет (или наоборот), эти обратные вызовы не вызываются в этом случае, и я еще не нашел способ, как это сделать. установите новый верхний контроллер в правильную ориентацию. Любые идеи?
Лопе
4
Я создал подкласс UINavigationController и установил его как window.rootController. Я реализовал все 3 метода, он отлично работает, когда вы меняете вращение устройства, проблема в том, что эти методы (и ничего, связанное с вращением) вызываются, когда вы открываете контроллер представления
Лопе
4
Если я нажимаю или выталкиваю из контроллера ландшафтного представления, тогда эта сила UIViewController меняется на ландшафт. Однако, если я поверну в портретный режим, он будет работать нормально и никогда не изменится на альбомный. Единственная проблема при нажатии или выскакивании из ландшафта. Пожалуйста, помогите
Тарик
63

Лучший способ специально для iOS6 отмечен в «iOS6 By Tutorials» команды Рэя Вендерлиха - http://www.raywenderlich.com/ и UINavigationControllerв большинстве случаев лучше, чем создание подклассов .

Я использую iOS6 с раскадровкой, которая включает UINavigationControllerнабор в качестве начального контроллера представления.

//AppDelegate.m - этот метод, к сожалению, недоступен до iOS6

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;

if(self.window.rootViewController){
    UIViewController *presentedViewController = [[(UINavigationController *)self.window.rootViewController viewControllers] lastObject];
    orientations = [presentedViewController supportedInterfaceOrientations];
}

return orientations;
}

//MyViewController.m - вернуть любые ориентации, которые вы хотите поддерживать для каждого UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
Фил
источник
1
Это лучшее решение для iOS 6
Homam
2
@Phil, на iOS 6 работает нормально. Но в некоторых случаях, например, если вы переходите с альбомной ориентации на портретную, это не работает. Есть идеи, почему это происходит?
Кирти Никам
1
Очень полезное решение. Для меня самое лучшее.
Оскар Кастельон
1
Работает на iOS 7 beta 6. В моем случае работает при переходе от альбомной ориентации к портретной.
Мартин Бергер
Я использую iOS 6, но это не работает. Он прерывается в строке «UIViewController * PresentViewController».
Марсель Марино
39

Этот ответ относится к вопросам, заданным в комментариях к сообщению OP:

Чтобы заставить представление отображаться в заданной ориентации, поместите в viewWillAppear следующее:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
    UIViewController *c = [[UIViewController alloc]init];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}

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

ОБНОВЛЕНИЕ для iOS7

Вышеуказанные методы теперь устарели, поэтому для iOS 7 используйте следующее:

UIApplication* application = [UIApplication sharedApplication];
if (application.statusBarOrientation != UIInterfaceOrientationPortrait)
{
     UIViewController *c = [[UIViewController alloc]init];
     [c.view setBackgroundColor:[UIColor redColor]];
     [self.navigationController presentViewController:c animated:NO completion:^{
            [self.navigationController dismissViewControllerAnimated:YES completion:^{
            }];
     }];
}

Интересно, что на момент написания либо подарок, либо увольнение должны быть анимированы. В противном случае вы получите белый экран. Понятия не имею, почему это заставляет его работать, но это действительно так! Визуальный эффект различается в зависимости от анимации.

Крейг Уоткинсон
источник
Спасибо, я попробую, когда найду несколько минут свободного времени
Лопе
@RohanAgarwal, он работает как рекламируется, я использую его здесь. Но вам также необходимо реализовать принятый код ответа, иначе он не сработает.
Деннис Манси
2
Кто-нибудь придумал, как заставить это работать с правильной анимацией вращения при этом? Немного неприятно видеть, как он переключается с портретной на ландшафтную без анимации. Он работает, просто надеясь, что он работает немного лучше.
Деннис Манси
@Craig Watkinson Это не работает в раскадровке. и presentModalViewController и dismissModalViewControllerAnimated устарели, если я использую PresentVirecontroller, тогда он не будет работать. Пожалуйста, помогите мне
Kalpesh
1
Для ios8 dismissViewControllerAnimated просто вылетает. Я обнаружил, что вызов [NWSAppDelegate sharedInstance] .window.rootViewController = nil; [NWSAppDelegate sharedInstance] .window.rootViewController = previousRootController работает нормально.
Алексей
36

Поэтому я столкнулся с той же проблемой при отображении модальных представлений только в портретной ориентации. Обычно я бы создал UINavigationController, установил viewControllerкак rootViewController, а затем отобразилUINavigationController как модальное представление. Но с iOS 6 viewControllerтеперь будет запрашивать у navigationController поддерживаемую ориентацию интерфейса (которая по умолчанию теперь предназначена только для iPad и всего, кроме перевернутого для iPhone).

Решение : мне пришлось создать подкласс UINavigationControllerи переопределить методы авторотации. Вид хромой.

- (BOOL)shouldAutorotate {
    return NO;
}

- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}
// pre-iOS 6 support 
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
скалистый
источник
1
не работает на моем. У меня был этот код с глобальными настройками для всех ориентаций
phil88530,
2
supportInterfaceOrientations должен возвращать NSUInteger, а не BOOL. См developer.apple.com/library/ios/#featuredarticles/...
tomwhipple
это сработало, для меня это tabbarcontroller, еще раз спасибо за ответ
otakuProgrammer
FWIW, мне тоже пришлось пойти по этому пути ... Больше ничего не работало. Спасибо.
Steve N
15

IOS 5

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{

    return (interfaceOrientation == UIInterfaceOrientationPortrait);

}

IOS 6

-(BOOL)shouldAutorotate{
    return YES;
}

-(NSInteger)supportedInterfaceOrientations{

    //    UIInterfaceOrientationMaskLandscape;
    //    24
    //
    //    UIInterfaceOrientationMaskLandscapeLeft;
    //    16
    //
    //    UIInterfaceOrientationMaskLandscapeRight;
    //    8
    //
    //    UIInterfaceOrientationMaskPortrait;
    //    2

    //    return UIInterfaceOrientationMaskPortrait; 
    //    or
          return 2;
}
Рошан Джалгаонкар
источник
Превосходно! Должен быть максимально вверху этой темы. Потому что это самый простой способ решить проблему
Alex
@Roshan Jalgaonkar В ios 6 это не работает для меня, мне нужен только портрет с кнопкой вниз, как я могу установить эту UIOrientation ....
Картик
@Karthik, вы должны включить поддерживаемые ротации в цели вашего приложения, чтобы это работало.
Alejandro Iván
@ AlejandroIván k thnx
Karthik
10

Я не согласен с ответом @aprato, потому что методы вращения UIViewController объявлены в самих категориях, что приводит к неопределенному поведению, если вы переопределяете его в другой категории. Безопаснее переопределить их в подклассе UINavigationController (или UITabBarController).

Кроме того, это не распространяется на сценарий, в котором вы нажимаете / представляете / выталкиваете из альбомной ориентации в вертикальную вертикальную ориентацию или наоборот. Чтобы решить эту сложную проблему (никогда не решавшуюся Apple), вам следует:

В iOS <= 4 и iOS> = 6:

UIViewController *vc = [[UIViewController alloc]init];
[self presentModalViewController:vc animated:NO];
[self dismissModalViewControllerAnimated:NO];
[vc release];

В iOS 5:

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

Это ДЕЙСТВИТЕЛЬНО заставит UIKit переоценить все ваши shouldAutorotate, supportedInterfaceOrientations и т. Д.

Рафаэль Нобре
источник
2
Первый из этих сбоев у меня вылетает независимо от версии iOS. Говорит, что увольнение не следует вызывать до окончания присутствия.
arsenius
@arsenius Можете опубликовать отрывок о том, как вы его используете? Пока он не анимирован, в нем не должно быть той проблемы, о которой вы упоминаете
Рафаэль Нобре
Я также поместил второй фрагмент в viewDidAppear, и он никак не помогает моей ситуации на iOS 6. Вопрос здесь: stackoverflow.com/questions/15654339/…
arsenius
Извините, последний комментарий. Перемещение кода iOS 5 в viewDidAppear создает своего рода бесконечный цикл со следующими выходными данными: - переполнение [UIApplication beginIgnoringInteractionEvents]. Игнорирование.
arsenius
3

У меня очень хороший подход к смешиванию https://stackoverflow.com/a/13982508/2516436 и https://stackoverflow.com/a/17578272/2516436

-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window{
    NSUInteger orientations = UIInterfaceOrientationMaskAllButUpsideDown;


    if(self.window.rootViewController){
        UIViewController *presentedViewController = [self topViewControllerWithRootViewController:self.window.rootViewController];
        orientations = [presentedViewController supportedInterfaceOrientations];
    }

    return orientations;
}

- (UIViewController*)topViewControllerWithRootViewController:(UIViewController*)rootViewController {
    if ([rootViewController isKindOfClass:[UITabBarController class]]) {
        UITabBarController* tabBarController = (UITabBarController*)rootViewController;
        return [self topViewControllerWithRootViewController:tabBarController.selectedViewController];
    } else if ([rootViewController isKindOfClass:[UINavigationController class]]) {
        UINavigationController* navigationController = (UINavigationController*)rootViewController;
        return [self topViewControllerWithRootViewController:navigationController.visibleViewController];
    } else if (rootViewController.presentedViewController) {
        UIViewController* presentedViewController = rootViewController.presentedViewController;
        return [self topViewControllerWithRootViewController:presentedViewController];
    } else {
        return rootViewController;
    }
}

и вернуть те ориентации, которые вы хотите поддерживать для каждого UIViewController

- (NSUInteger)supportedInterfaceOrientations{
    return UIInterfaceOrientationMaskPortrait;
}
Алекс Герра
источник
1

У меня есть относительно сложное универсальное приложение, использующее UISplitViewController и UISegmentedController, и несколько представлений, которые должны быть представлены в ландшафте с использованием presentViewController . Используя методы, предложенные выше, я смог заставить iPhone ios 5 и 6 работать нормально, но по какой-то причине iPad просто отказался отображаться как альбомный. Наконец, я нашел простое решение (реализованное после нескольких часов чтения, проб и ошибок), которое работает как для устройств, так и для iOS 5 и 6.

Шаг 1) На контроллере укажите требуемую ориентацию (примерно как указано выше)

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

-(BOOL)shouldAutorotate
{
    return YES;
}

-(NSUInteger)supportedInterfaceOrientations
{
    NSInteger mask = UIInterfaceOrientationMaskLandscape;
    return mask;

}

Шаг 2) Создайте простой подкласс UINavigationController и реализуйте следующие методы.

-(BOOL)shouldAutorotate {
        return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
        return UIInterfaceOrientationMaskLandscape;
}

Шаг 3) Представьте свой viewController

vc = [[MyViewController alloc]init];
MyLandscapeNavigationController *myNavigationController = [[MyLandscapeNavigationController alloc] initWithRootViewController:vc];
[self myNavigationController animated:YES completion:nil];

Надеюсь, это кому-то поможет.

user216661
источник
1

Чтобы не было скучно, но не могли бы вы поделиться своим подклассом? Спасибо.

edit: ну, наконец, я сделал это, подкласс было очень просто сделать. Я просто должен был объявить navigationControllerв AppDelegateкачестве UINavigationControllerSubclassвместо значения по умолчанию UINavigationController, то редактировал подкласс с:

- (BOOL)shouldAutorotate {
    return _shouldRotate;
}

поэтому я могу установить любое представление, которое хочу повернуть или нет, позвонив по адресу viewDidLoad

_navController = (UINavigationController *)self.navigationController;
[_navController setShouldRotate : YES / NO]

Надеюсь, эта настройка поможет и другим, спасибо за совет!

Совет: используйте

- (NSUInteger)supportedInterfaceOrientations

в ваших контроллерах просмотра, поэтому вы не получите желаемый портретный вид в альбомной или наоборот.

Роланд
источник
0

Я сам не тестировал, но в документации указано, что теперь вы можете переопределить эти методы: supportedInterfaceOrientationsиpreferredInterfaceOrientationForPresentation .

Вероятно, вы сможете добиться того, чего хотите, установив только ту ориентацию, которая вам нужна этими методами.

J_D
источник
0

Ответы с использованием подклассов или категорий, позволяющих использовать VC в классах UINavigationController и UITabBarController, работают хорошо. Не удалось запустить модальное окно с портретной ориентацией из контроллера панели вкладок с альбомной ориентацией. Если вам нужно это сделать, воспользуйтесь уловкой отображения и скрытия неанимированного модального представления, но сделайте это в методе viewDidAppear . У меня это не сработало в viewDidLoad или viewWillAppear.

Кроме того, приведенные выше решения работают нормально.

Питер
источник
0

Для Monotouch это можно сделать так:

public override UIInterfaceOrientationMask GetSupportedInterfaceOrientations()
    {
    return UIInterfaceOrientationMask.LandscapeRight;
}

public override UIInterfaceOrientation PreferredInterfaceOrientationForPresentation()
    {
    return UIInterfaceOrientation.LandscapeRight;
}
Сомони
источник
-1

Просто перейдите в project.plist, затем добавьте Поддерживаемую ориентацию интерфейса, а затем добавьте только Портрет (нижняя кнопка главного экрана) и Портрет (верхняя кнопка главного экрана).

Вы можете добавить или удалить ориентацию в соответствии с требованиями вашего проекта.

Благодарность

Мухаммад Саад Ансари
источник
1
это о конкретном контроллере представления, а не для всего приложения.
Мухаммад Ризван
-2

1) Проверьте настройки вашего проекта и info.plist и убедитесь, что выбраны только те ориентации, которые вам нужны.

2) добавьте следующие методы в самый верхний контроллер представления (контроллер навигации / контроллер панели вкладок)

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

3) добавьте следующие методы в делегат вашего приложения

- (NSUInteger) supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait;

}

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
    return UIInterfaceOrientationMaskPortrait;

}
Эханна
источник
-3

Поместите это в файл .m каждого, ViewControllerкоторый вы не хотите вращать:

- (NSUInteger)supportedInterfaceOrientations
{
    //return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;
    return UIInterfaceOrientationMaskPortrait;
}

См. Здесь для получения дополнительной информации.

Военно-морской стрелок
источник