web-dev-qa-db-fra.com

IOS Orientation du dispositif à 6 forces par rapport au paysage

J'ai donné une application avec par exemple 10 contrôleurs de vue. J'utilise le contrôleur de navigation pour les charger/décharger. 

Tous sauf un sont en mode portrait. Supposons que le 7ème VC soit en paysage. J'ai besoin que cela soit présenté dans le paysage quand il est chargé. 

Veuillez suggérer un moyen de forcer l'orientation du portrait au paysage dans IOS 6 (et il sera également utile de travailler dans IOS 5).

Voici comment je le faisaisAVANTIOS 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);
}

Présenter et rejeter un modal VC obligeait l'application à revoir son orientation. shouldAutorotateToInterfaceOrientation était donc appelé.

Ce que j'ai essayé dans IOS 6:

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

En charge, le contrôleur reste en mode portrait. Après la rotation de l'appareil, l'orientation change parfaitement. Mais je dois faire en sorte que le contrôleur tourne automatiquement en mode paysage lors du chargement. Par conséquent, l'utilisateur devra faire pivoter l'appareil pour voir les données correctement.

Un autre problème: après avoir retourné l'appareil en mode portrait, l'orientation passe en mode portrait, bien que je l'aie spécifiée dans supportedInterfaceOrientations uniquement UIInterfaceOrientationMaskLandscape. Pourquoi ça arrive?

En outre,NONEde ci-dessus 3 méthodes sont appelées.

Quelques données (utiles):

  1. Dans mon fichier Plist, j'ai spécifié 3 orientations - toutes à l’envers.
  2. Le projet a été démarré sous Xcode 4.3 IOS 5. Toutes les classes, y compris xibs, ont été créées avant Xcode 4.5 IOS 6. J'utilise maintenant la dernière version.
  3. Dans le fichier plist, la barre d'état est définie sur visible.
  4. Dans le fichier xib (celui que je veux être en mode paysage), la barre d'état est "Aucune", l'orientation est définie sur paysage.

Toute aide est appréciée. Merci. 

57
John Smith

Ok, les amis, je vais poster ma solution.

Ce que j'ai:

  1. Une application basée sur la vue, avec plusieurs contrôleurs de vue. (C'était basé sur la navigation, mais je devais le rendre basé sur l'affichage, à cause de problèmes d'orientation).
  2. Tous les contrôleurs de vue sont en portrait, à l'exception de one - landscapeLeft.

Les tâches:

  1. L'un de mes contrôleurs de vue doit automatiquement basculer en mode paysage, quelle que soit la manière dont l'utilisateur gère le périphérique. Tous les autres contrôleurs doivent être en portrait et, après avoir quitté le contrôleur de paysage, l'application doit forcer la rotation en portrait, peu importe, encore une fois, la façon dont l'utilisateur détient le périphérique.
  2. Cela doit fonctionner comme sur IOS 6.x comme sur IOS 5.x

Aller!

( Update Suppression des macros suggérées par @Ivan Vučica)

Dans tous vos contrôleurs de vue PORTRAIT, substituez les méthodes d'autorotation comme ceci:

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

Vous pouvez voir les 2 approches: une pour IOS 5 et une autre pour IOS 6.

Idem pour votre contrôleur de vue LANDSCAPE, avec quelques ajouts et modifications:  

- (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;
}

ATTENTION: pour forcer l’autorotation dans IOS 5 vous devriez ajouter ceci:

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

De manière analogue, lorsque vous quittez le contrôleur LANDSCAPE, quel que soit le contrôleur que vous chargez, vous devez forcer à nouveau l'autorotation de IOS 5, mais vous allez maintenant utiliser UIDeviceOrientationPortrait lorsque vous accédez à un contrôleur PORTRAIT:

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

Maintenant, la dernière chose (et c'est un peu bizarre) - vous devez changer la façon dont vous passez d'un contrôleur à un autre, en fonction de l'IOS:

Créez une classe NSObject "Schalter" ("Switch" en allemand). 

Dans Schalter.h, dites:

#import <Foundation/Foundation.h>

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

Dans Schalter.m, dites:

#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

C’est comme ça que vous utilisez Schalter (supposons que vous passiez du contrôleur Warehouse au contrôleur Products):

#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

Bien sûr, vous devez libérer l'objet instance_to_products:

- (void)dealloc{
     [instance_to_products release];
     [super dealloc];
}

Eh bien, c'est ça. Ne pas hésiter à voter, je m'en fiche. Ceci est pour ceux qui recherchent des solutions, pas pour la réputation. Cheers! Sava Mazare.

43
John Smith

Cela devrait fonctionner, il est similaire à la version antérieure à iOS 6, mais avec une UINavigationController:

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

J'appelle cela avant de pousser la prochaine UIViewController. Cela forcera la prochaine UIViewController poussée à être affichée en mode Portrait même si la UIViewController actuelle est en Paysage (devrait également fonctionner pour Portrait à Paysage). Fonctionne sur iOS 4 + 5 + 6 pour moi.

34
Chunkylover53

Je pense que la meilleure solution consiste à s’en tenir à la documentation officielle d’Apple. J'utilise donc les méthodes suivantes et tout fonctionne très bien sur iOS 5 et 6. Dans mon VC, je remplace les méthodes suivantes:

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

Méthodes pour iOS 6, la première méthode renvoie le masque d'orientation pris en charge (comme leur nom l'indique).

-(NSUInteger)supportedInterfaceOrientations{

    return UIInterfaceOrientationMaskPortrait;
}

la seconde indique à votre VC l'orientation privilégiée de l'interface lorsque VC doit être affiché. 

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}

Il suffit de changer Portrait pour l’orientation souhaitée;) Cette solution fonctionne bien, je n’aime pas l’idée de créer des macros et d’autres éléments, ce qui permet de résoudre cette solution simple. J'espère que cela vous aidera ...

14
Skodik.o

J'ai eu le même problème, 27 vues dans mon application dont 26 en portrait et une seule dans toutes les orientations (une visionneuse d'images :)) . Ajouter la macro sur chaque classe et remplacer la navigation n'était pas une solution que j'étais confortable avec...

Donc, je voulais garder la mécanique de UINavigationController dans mon application et ne pas la remplacer par un autre code.

Que faire:

@ 1 Dans le délégué d'application dans la méthode 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 Parce que navigationController répondra simplement avec YES pour l’autorotation, nous devons ajouter quelques limitations: Étendez UINavicationController -> YourNavigationController et reliez-le dans Interface Builder.

@ 3 Remplacez les "nouvelles méthodes" du contrôleur de navigation.

Étant donné que cette classe est personnalisée uniquement pour cette application, elle peut prendre la responsabilité de ses contrôleurs et répondre à leur place.

-(BOOL)shouldAutorotate {

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

J'espère que cela t'aidera, 

7
Vlad Cioaba

Depuis le Notes de version iOS 6 :

À présent, les conteneurs iOS (tels que UINavigationController) ne consultent pas leurs enfants pour déterminer s’ils doivent effectuer une auto-rotation.

Votre rootViewController transmet-il le message shouldAutoRotate à la hiérarchie ViewController de votre VC?

3
sjwarner

J'ai utilisé la même méthode que l'OP pre-ios6 (présenter et rejeter un VC modal) pour afficher un seul contrôleur de vue en mode paysage (tous les autres en portrait). Il a éclaté dans iOS 6 avec le paysage VC apparaissant en portrait.

Pour résoudre ce problème, je viens d'ajouter la méthode preferredInterfaceOrientationForPresentation dans le paysage VC. Semble fonctionner correctement pour os 5 et os 6 maintenant.

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

- (BOOL)shouldAutorotate
{
return NO;
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{    
return UIInterfaceOrientationLandscapeLeft;
}
2
user1581123

Hé les gars, après avoir essayé beaucoup de solutions différentes sans succès, je suis sorti avec la solution suivante, j'espère que ça aide !. 

J'ai préparé une recette :).

Problème: Vous devez modifier l’orientation des contrôleurs de vue à l’aide de navigationcontroller dans ios 6. 

Solution:

navigation suggested

step 1. un UIviewcontroler initial pour déclencher les séquences modales en paysage et portrait UInavigationControllers comme le montre l'image ....

plus profondément dans UIViewController1, nous avons besoin d'actions de 2 segments selon la variable globale chez Appdelegate ....

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

}

nous avons aussi besoin d'un moyen de revenir à portrait & | paysage....

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

step 2. le premier Pushi UiViewControllers à chaque NavigationController va avec...

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

-(BOOL)shouldAutorotate{
    return YES;
}

step 3. Nous écrasons la méthode supportéeInterfaceOrientations de la sous-classe de UInavigationController ....

dans votre navigationController custom nous avons .....

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

        return UIInterfaceOrientationMaskPortrait;
    }
    else{
        return UIInterfaceOrientationMaskLandscape;

    }

}

step 4. Sur le storyboard ou par le code, définissez le drapeau wantedFullScreenLayout sur yes, aux deux contrôleurs de navigation en portrait et en paysage. 

2
47tucanae

Essayez de passer à une UINavigationController qui utilise une catégorie ou est sous-classé pour spécifier l’orientation souhaitée, puis passez au VC souhaité. Lire plus ici .

1
Michael Mangold

Comme alternative, vous pouvez faire la même chose en utilisant des blocs:

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

Appelez-le également avant de pousser la nouvelle vue.

1
Raspu

J'ai eu le même problème. Si vous souhaitez forcer un contrôleur de vue particulier à apparaître en mode paysage, faites-le avant de le placer dans la pile de navigation.

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];
0
Norbert Antal

Je l'ai résolu en sous-classant UINavigationController et en substituant les arguments supportés du contrôleur de navigation comme suit:

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

Tous les contrôleurs implémentés supportéInterfaceOrientations avec les orientations souhaitées.

0
Zeev Vax

Allez dans votre fichier Info.plist et faites le changement enter image description here