IOS 6 принудительная ориентация устройства на ландшафт


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

все, кроме одного, находятся в портретном режиме. Предположим, что 7-й VC находится в ландшафте. Мне нужно, чтобы он был представлен в ландшафте, когда он загружается.

пожалуйста, предложите способ заставить ориентацию перейти от портретной к альбомной в IOS 6 (и это будет хорошо работать в iOS 5, а).

вот как я это делаю до IOS 6:

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    UIViewController *c = [[[UIViewController alloc]init] autorelease];
    [self presentModalViewController:c animated:NO];
    [self dismissModalViewControllerAnimated:NO];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

представление и отклонение модального VC заставляло приложение пересматривать свою ориентацию, поэтому shouldAutorotateToInterfaceOrientation был вызван.

что я пробовал в IOS 6:

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

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

еще одна проблема: после поворота устройства обратно в портрет, ориентация переходит в портрет, хотя я указал в supportedInterfaceOrientations только UIInterfaceOrientationMaskLandscape. Почему это происходит?

и нет из выше 3 методов вызываются.

некоторые (полезные) данные:

  1. в моем файле plist я указал 3 ориентации - все, кроме вверх ногами.
  2. проект был запущен в Xcode 4.3 IOS 5. Все классы, включая xibs, были созданы до Xcode 4.5 IOS 6, теперь я использую последнюю версию.
  3. в файле plist строка состояния имеет значение видимый.
  4. в файле xib (тот, который я хочу быть в альбомной ориентации) строка состояния "нет", ориентация установлена в альбомной ориентации.

любая помощь приветствуется. Спасибо.

13 56

13 ответов:

хорошо, ребята, я опубликую свое решение.

что у меня есть:

  1. приложение на основе представления, с несколькими контроллерами представления. (Это была навигация на основе, но я должен был сделать его вид на основе, из-за проблем ориентации).
  2. все контроллеры вида являются портретными, за исключением одного-landscapeLeft.

задачи:

  1. один из моих контроллеров вида должен автоматически поворачиваться в альбомную ориентацию, независимо от того, как пользователь держит устройство. Все остальные контроллеры должны быть портретными, и после выхода из ландшафтного контроллера приложение должно принудительно поворачиваться к портрету, независимо от того, как пользователь держит устройство.
  2. это должно работать как на IOS 6.x как на IOS 5.x

вперед!

(обновление удалены макросы, предложенные @Ivan Vučica)

во всех ваших контроллерах портретного вида переопределяются методы авторотации, такие как это:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    return (toInterfaceOrientation == UIInterfaceOrientationPortrait);
}
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

вы можете увидеть 2 подхода: один для IOS 5 и другой для IOS 6.

то же самое для вашего контроллера ландшафтного вида, с некоторыми дополнениями и изменениями:

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation{
    [image_signature setImage:[self resizeImage:image_signature.image]];
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft);
}
-(BOOL)shouldAutorotate {
    return YES;
}
- (NSUInteger)supportedInterfaceOrientations {
    [image_signature setImage:[self resizeImage:image_signature.image]];
    return UIInterfaceOrientationMaskLandscapeLeft;
}

внимание: для принудительной авторотации в IOS 5 вы должны добавить это:

- (void)viewDidLoad{
    [super viewDidLoad];
    if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
        [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationLandscapeLeft animated:NO];    
}

аналогично, после того, как вы покинете ландшафтный контроллер, какой бы контроллер вы ни загрузили, вы должны снова заставить авторотация для IOS 5, но теперь вы будете использовать UIDeviceOrientationPortrait, как вы идете к портретному контроллеру:

- (void)viewDidLoad{
        [super viewDidLoad];
        if ([[[UIDevice currentDevice] systemVersion] floatValue] < 6.0)
            [[UIApplication sharedApplication] setStatusBarOrientation:UIDeviceOrientationPortrait animated:NO];    
    }

теперь последнее (и это немного странно) - вы должны изменить способ переключения с одного контроллера на другой, в зависимости от IOS:

создайте класс NSObject "Schalter" ("переключатель" с немецкого языка).

В Coupe ' Спортивный.ч. сказала:

#import <Foundation/Foundation.h>

@interface Schalter : NSObject
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease;
@end

В Coupe ' Спортивный.м говорю:

#import "Schalter.h"
#import "AppDelegate.h"

@implementation Schalter
+ (void)loadController:(UIViewController*)VControllerToLoad andRelease:(UIViewController*)VControllerToRelease{

    //adjust the frame of the new controller
    CGRect statusBarFrame = [[UIApplication sharedApplication] statusBarFrame];
    CGRect windowFrame = [[UIScreen mainScreen] bounds];
    CGRect firstViewFrame = CGRectMake(statusBarFrame.origin.x, statusBarFrame.size.height, windowFrame.size.width, windowFrame.size.height - statusBarFrame.size.height);
    VControllerToLoad.view.frame = firstViewFrame;

    //check version and go
    if (IOS_OLDER_THAN_6)
        [((AppDelegate*)[UIApplication sharedApplication].delegate).window addSubview:VControllerToLoad.view];
    else
        [((AppDelegate*)[UIApplication sharedApplication].delegate).window setRootViewController:VControllerToLoad];

    //kill the previous view controller
    [VControllerToRelease.view removeFromSuperview];
}
@end

теперь, это, как вы используйте Schalter (предположим, вы переходите от контроллера склада к контроллеру продуктов):

#import "Warehouse.h"
#import "Products.h"

@implementation Warehouse
Products *instance_to_products;

- (void)goToProducts{
    instance_to_products = [[Products alloc] init];
    [Schalter loadController:instance_to_products andRelease:self];
}

bla-bla-bla your methods

@end

конечно, вы должны освободить

Это должно работать, это похоже на версию до iOS 6, но с UINavigationController:

UIViewController *portraitViewController = [[UIViewController alloc] init];
UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:portraitViewController];
[self.navigationController presentModalViewController:nc animated:NO];
[self.navigationController dismissModalViewControllerAnimated:NO];

я называю это, прежде чем я нажимаю на следующий UIViewController. Это заставит следующий толкнул UIViewController для отображения в портретном режиме, даже если ток UIViewController находится в ландшафте (должен работать для портрета в ландшафт тоже). Работает на iOS 4+5+6 для меня.

Я думаю, что лучшее решение-придерживаться официальной документации apple. Поэтому в соответствии с этим я использую следующие методы, и все работает очень хорошо на iOS 5 и 6. В моем VC я переопределяю следующие методы:

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

методы для iOS 6, Первый метод возвращает поддерживаемую маску ориентации (как указано в их названии)

-(NSUInteger)supportedInterfaceOrientations{

    return UIInterfaceOrientationMaskPortrait;
}

второй, который говорит ваш VC, который является предпочтительной ориентацией интерфейса, когда VC будет отображаться.

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

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

у меня была та же проблема, 27 просмотров в моем приложении, из которых 26 в портрете и только один во всех ориентациях ( просмотрщик изображений :) ). Добавление макроса на каждый класс и замена навигации не было решением, с которым мне было комфортно...

Итак, я хотел сохранить механику UINavigationController в своем приложении и не заменять ее другим кодом.

Что делать:

@1 в делегате приложения в методе didFinishLaunchingWithOptions

if ([[UIDevice currentDevice].systemVersion floatValue] < 6.0)
{
    // how the view was configured before IOS6
    [self.window addSubview: navigationController.view];
    [self.window makeKeyAndVisible];
}
else
{
    // this is the code that will start the interface to rotate once again
    [self.window setRootViewController: self.navigationController];
}

@2 Поскольку navigationController просто ответит Да для авторотации нам нужно добавить некоторые ограничения: Расширьте UINavicationController - > YourNavigationController и свяжите его в Построителе интерфейса.

@3 переопределить "anoying новые методы" от навигационного контроллера.

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

-(BOOL)shouldAutorotate {

    if ([self.viewControllers firstObject] == YourObject)
    {
         return YES;
    }
    return NO;
}
- (NSUInteger)supportedInterfaceOrientations {
     if ([self.viewControllers firstObject] == YourObject)
    {
         return UIINterfaceOrientationMaskLandscape;
    }
    return UIInterfaceOrientationMaskPortrait;
}

Я надеюсь, что это поможет вам,

С iOS 6 примечания к выпуску:

Теперь контейнеры iOS (такие как UINavigationController) не консультируются со своими детьми, чтобы определить, следует ли им авторотировать.

ваша rootViewController передать shouldAutoRotate сообщение от ViewController иерархия для вашего ВК?

я использовал тот же метод, что и OP pre-ios6 (представить и отклонить модальный VC), чтобы показать один контроллер вида в ландшафтном режиме (все остальные в портретном). Он сломался в ios6 с пейзажем VC, показанным в портрете.

чтобы исправить это, я просто добавил метод preferredInterfaceOrientationForpresentation в ландшафтном VC. Кажется, теперь отлично работает для os 5 и os 6.

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

- (BOOL)shouldAutorotate
{
return NO;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{    
return UIInterfaceOrientationLandscapeLeft;
}

Эй, ребята после tryng много различных возможных решений без успеха я вышел со следующим решением надеюсь, что это поможет!.

Я приготовил рецепт :).

: вам нужно изменить ориентацию viewcontrollers с помощью navigationcontroller в ios 6.

устранение:

navigation suggested

Шаг 1. один начальный UIviewcontroler для запуска модальных сегментов в ландшафт и портрет UInavigationControllers как показано на рисунке....

более глубоко в UIViewController1 нам нужно 2 сегментирует действия в соответствии с глобальной переменной в Appdelegate....

-(void)viewDidAppear:(BOOL)animated{
    if([globalDelegate changeOrientation]==0){
        [self performSegueWithIdentifier:@"p" sender:self];
    }
    else{
        [self performSegueWithIdentifier:@"l" sender:self];
    }

}

также нам нужно вернуться к портрету и / пейзажу....

- (IBAction)dimis:(id)sender {
    [globalDelegate setChangeOrientation:0];
    [self dismissViewControllerAnimated:NO completion:nil];
}

Шаг 2. первый нажал UiViewControllers на каждом NavigationController идет с...

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

-(BOOL)shouldAutorotate{
    return YES;
}

Шаг 3. мы перезаписываем метод supportedInterfaceOrientations на подкласс UInavigationController....

в вашем customNavigationController у нас есть .....

-(NSUInteger)supportedInterfaceOrientations{
    if([self.visibleViewController isKindOfClass:[ViewController2 class]]){

        return UIInterfaceOrientationMaskPortrait;
    }
    else{
        return UIInterfaceOrientationMaskLandscape;

    }

}

Шаг 4. в раскадровке или по коду установите флаг wantsFullScreenLayout в yes, как для портретных, так и для ландшафтных uinavigationcontrollers.

попробуйте segueing к UINavigationController который использует категорию или подкласс, чтобы указать желаемую ориентацию, а затем перейти к желаемому VC. Читать дальше здесь.

в качестве альтернативы вы можете сделать то же самое используя блоки:

UIViewController *viewController    = [[UIViewController alloc] init];
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:viewController animated:NO completion:^{
    [self dismissViewControllerAnimated:NO completion:nil];
}];

кроме того, вызовите его перед нажатием нового представления.

перейти к вам информация.plist файл и внести изменения enter image description here

У меня была та же проблема. Если вы хотите, чтобы определенный контроллер вида отображался в альбомной ориентации, сделайте это прямо перед тем, как поместить его в стек навигации.

UIInterfaceOrientation currentOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if (currentOrientation == UIInterfaceOrientationPortrait ||
            currentOrientation == UIInterfaceOrientationPortraitUpsideDown)
            [[UIDevice currentDevice] setOrientation:UIInterfaceOrientationLandscapeLeft];

        UIViewController *vc = [[UIViewController alloc] init];
        [self.navigationController pushViewController:vc animated:YES];
        [vc release];

Я решил это путем подкласса UINavigationController и переопределения supportedInterfaceOrientations навигационного контроллера следующим образом:

- (NSUInteger)supportedInterfaceOrientations
{
     return [[self topViewController] supportedInterfaceOrientations];
}

все контроллеры реализовали supportedInterfaceOrientations с их желаемыми ориентациями.

я использовал следующее решение. В одном контроллере вида, который имеет другую ориентацию, чем все остальные, я добавил проверку ориентации в prepareForSegue метод. Если контроллеру вида назначения требуется ориентация интерфейса, отличная от текущей, то отправляется сообщение, которое заставляет интерфейс вращаться во время seque.

#import <objc/message.h>

...

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if(UIDeviceOrientationIsLandscape(self.interfaceOrientation))
    {
        UIInterfaceOrientation destinationOrientation;

        if ([[segue destinationViewController] isKindOfClass:[UINavigationController class]])
        {
            UINavigationController *navController = (UINavigationController *)[segue destinationViewController];
            destinationOrientation = [navController.topViewController preferredInterfaceOrientationForPresentation];
        } else
        {
            destinationOrientation = [[segue destinationViewController] preferredInterfaceOrientationForPresentation];
        }

        if ( destinationOrientation == UIInterfaceOrientationPortrait )
        {
            if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
            {
                objc_msgSend([UIDevice currentDevice], @selector(setOrientation:), UIInterfaceOrientationPortrait );
            }
        }
    }
}